Repository: cta-observatory/ctapipe
Pull request #2408 (2023-10-10 16:03:13)

Fix broken urls in README
This fixes broken urls in the README after the restructuring of the docs.

maxnoe: Rebasing with main will fix the docs build
maxnoe: Something went wrong in your rebasing
aknierim: > Something went wrong in your rebasing

Yeah, can't figure out what, though...
maxnoe: Did you update upstream before the rebase?

```
git fetch upstream
git rebase upstream/main
```
?
aknierim: Yup, which is why I'm confused

Patch:
diff --git a/README.rst b/README.rst
index b477415b..dc241c49 100644
--- a/README.rst
+++ b/README.rst
@@ -71,11 +71,11 @@ or via::
 
   pip install ctapipe
 
-**Note**: to install a specific version of ctapipe take look at the documentation `here <https://ctapipe.readthedocs.org/en/latest/getting_started_users/>`__.
+**Note**: to install a specific version of ctapipe take look at the documentation `here <https://ctapipe.readthedocs.io/en/latest/user-guide/index.html>`__.
 
 **Note**: ``mamba`` is a C++ reimplementation of conda and can be found `here <https://github.com/mamba-org/mamba>`__.
 
 Note this is *pre-alpha* software and is not yet stable enough for end-users (expect large API changes until the first stable 1.0 release).
 
 Developers should follow the development install instructions found in the
-`documentation <https://ctapipe.readthedocs.org/en/latest/getting_started/>`__.
+`documentation <https://ctapipe.readthedocs.io/en/latest/developer-guide/getting-started.html>`__.
diff --git a/ctapipe/containers.py b/ctapipe/containers.py
index 3fbb88a7..cb4282c5 100644
--- a/ctapipe/containers.py
+++ b/ctapipe/containers.py
@@ -772,7 +772,6 @@ class SimulationConfigContainer(Container):
     Configuration parameters of the simulation
     """
 
-    run_number = Field(np.int32(-1), description="Original sim_telarray run number")
     corsika_version = Field(nan, description="CORSIKA version * 1000")
     simtel_version = Field(nan, description="sim_telarray version * 1000")
     energy_range_min = Field(
@@ -921,17 +920,12 @@ class ReconstructedGeometryContainer(Container):
         "reconstructed core position uncertainty along tilted frame Y axis",
         unit=u.m,
     )
-    h_max = Field(
-        nan * u.m,
-        "reconstructed vertical height above sea level of the shower maximum",
-        unit=u.m,
-    )
+    h_max = Field(nan * u.m, "reconstructed height of the shower maximum", unit=u.m)
     h_max_uncert = Field(nan * u.m, "uncertainty of h_max", unit=u.m)
-
     is_valid = Field(
         False,
         (
-            "Geometry validity flag. True if the shower geometry"
+            "direction validity flag. True if the shower direction"
             "was properly reconstructed by the algorithm"
         ),
     )
diff --git a/ctapipe/instrument/camera/geometry.py b/ctapipe/instrument/camera/geometry.py
index 8d22dc6e..50c227db 100644
--- a/ctapipe/instrument/camera/geometry.py
+++ b/ctapipe/instrument/camera/geometry.py
@@ -954,13 +954,12 @@ class CameraGeometry:
         pix_indices: Pixel index or array of pixel indices. Returns -1 if position falls
                     outside camera
         """
+
         if not self._all_pixel_areas_equal:
             logger.warning(
                 " Method not implemented for cameras with varying pixel sizes"
             )
         unit = x.unit
-        scalar = x.ndim == 0
-
         points_searched = np.dstack([x.to_value(unit), y.to_value(unit)])
         circum_rad = self._pixel_circumradius[0].to_value(unit)
         kdtree = self._kdtree
@@ -970,9 +969,8 @@ class CameraGeometry:
         del dist
         pix_indices = pix_indices.flatten()
 
-        invalid = np.iinfo(pix_indices.dtype).min
         # 1. Mark all points outside pixel circumeference as lying outside camera
-        pix_indices[pix_indices == self.n_pixels] = invalid
+        pix_indices[pix_indices == self.n_pixels] = -1
 
         # 2. Accurate check for the remaing cases (within circumference, but still outside
         # camera). It is first checked if any border pixel numbers are returned.
@@ -1008,9 +1006,17 @@ class CameraGeometry:
                 )
                 del dist_check
                 if index_check != insidepix_index:
-                    pix_indices[index] = invalid
+                    pix_indices[index] = -1
+
+        # print warning:
+        for index in np.where(pix_indices == -1)[0]:
+            logger.warning(
+                " Coordinate ({} m, {} m) lies outside camera".format(
+                    points_searched[0][index, 0], points_searched[0][index, 1]
+                )
+            )
 
-        return np.squeeze(pix_indices) if scalar else pix_indices
+        return pix_indices if len(pix_indices) > 1 else pix_indices[0]
 
     @staticmethod
     def simtel_shape_to_type(pixel_shape):
diff --git a/ctapipe/io/simteleventsource.py b/ctapipe/io/simteleventsource.py
index 70e8e93f..632277a5 100644
--- a/ctapipe/io/simteleventsource.py
+++ b/ctapipe/io/simteleventsource.py
@@ -49,7 +49,7 @@ from ..containers import (
 from ..coordinates import CameraFrame, shower_impact_distance
 from ..core import Map
 from ..core.provenance import Provenance
-from ..core.traits import Bool, ComponentName, Float, Integer, Undefined, UseEnum
+from ..core.traits import Bool, ComponentName, Float, Undefined, UseEnum
 from ..instrument import (
     CameraDescription,
     CameraGeometry,
@@ -483,12 +483,6 @@ class SimTelEventSource(EventSource):
         ),
     ).tag(config=True)
 
-    override_obs_id = Integer(
-        default_value=None,
-        allow_none=True,
-        help="Use the given obs_id instead of the run number from sim_telarray",
-    ).tag(config=True)
-
     def __init__(self, input_url=Undefined, config=None, parent=None, **kwargs):
         """
         EventSource for simtelarray files using the pyeventio library.
@@ -707,10 +701,11 @@ class SimTelEventSource(EventSource):
             SimulationConfigContainer), but with the lat/lon set to (0,0), i.e.
             on "Null Island"
         """
+        obs_id = self.file_.header["run"]
         return EarthLocation(
             lon=0 * u.deg,
             lat=0 * u.deg,
-            height=self._simulation_config[self.obs_id].prod_site_alt,
+            height=self._simulation_config[obs_id].prod_site_alt,
         )
 
     @staticmethod
@@ -748,7 +743,7 @@ class SimTelEventSource(EventSource):
                 pseudo_event_id -= 1
                 event_id = pseudo_event_id
 
-            obs_id = self.obs_id
+            obs_id = self.file_.header["run"]
 
             trigger = self._fill_trigger_info(array_event)
             if trigger.event_type == EventType.SUBARRAY:
@@ -1012,14 +1007,12 @@ class SimTelEventSource(EventSource):
         point in time, this dictionary will always have
         length 1.
         """
-        obs_id = self.obs_id
+        assert len(self.obs_ids) == 1
+        obs_id = self.obs_ids[0]
         # With only one run, we can take the first entry:
         mc_run_head = self.file_.mc_run_headers[-1]
 
         simulation_config = SimulationConfigContainer(
-            run_number=self.file_.header["run"],
-            detector_prog_start=mc_run_head["detector_prog_start"],
-            detector_prog_id=mc_run_head["detector_prog_id"],
             corsika_version=mc_run_head["shower_prog_vers"],
             simtel_version=mc_run_head["detector_prog_vers"],
             energy_range_min=mc_run_head["E_range"][0] * u.TeV,
@@ -1031,6 +1024,8 @@ class SimTelEventSource(EventSource):
             spectral_index=mc_run_head["spectral_index"],
             shower_prog_start=mc_run_head["shower_prog_start"],
             shower_prog_id=mc_run_head["shower_prog_id"],
+            detector_prog_start=mc_run_head["detector_prog_start"],
+            detector_prog_id=mc_run_head["detector_prog_id"],
             n_showers=mc_run_head["n_showers"],
             shower_reuse=mc_run_head["n_use"],
             max_alt=_clip_altitude_if_close(mc_run_head["alt_range"][1]) * u.rad,
@@ -1061,20 +1056,11 @@ class SimTelEventSource(EventSource):
         """
 
         az, alt = self.file_.header["direction"]
-
-        # this event source always contains only a single OB, so we can
-        # also assign a single obs_id
-        if self.override_obs_id is not None:
-            self.obs_id = self.override_obs_id
-        else:
-            self.obs_id = self.file_.header["run"]
-
-        # simulations at the moment do not have SBs, use OB id
-        self.sb_id = self.obs_id
+        obs_id = self.file_.header["run"]
 
         sb_dict = {
-            self.sb_id: SchedulingBlockContainer(
-                sb_id=np.uint64(self.sb_id),
+            obs_id: SchedulingBlockContainer(
+                sb_id=np.uint64(obs_id),  # simulations have no SBs, use OB id
                 sb_type=SchedulingBlockType.OBSERVATION,
                 producer_id="simulation",
                 observing_mode=ObservingMode.UNKNOWN,
@@ -1083,9 +1069,9 @@ class SimTelEventSource(EventSource):
         }
 
         ob_dict = {
-            self.obs_id: ObservationBlockContainer(
-                obs_id=np.uint64(self.obs_id),
-                sb_id=np.uint64(self.sb_id),
+            obs_id: ObservationBlockContainer(
+                obs_id=np.uint64(obs_id),
+                sb_id=np.uint64(obs_id),  # see comment above
                 producer_id="simulation",
                 state=ObservationBlockState.COMPLETED_SUCCEDED,
                 subarray_pointing_lat=alt * u.rad,
diff --git a/ctapipe/reco/hillas_intersection.py b/ctapipe/reco/hillas_intersection.py
index 0906cf0f..d7288b58 100644
--- a/ctapipe/reco/hillas_intersection.py
+++ b/ctapipe/reco/hillas_intersection.py
@@ -44,7 +44,6 @@ INVALID = ReconstructedGeometryContainer(
 )
 
 FOV_ANGULAR_DISTANCE_LIMIT_RAD = (45 * u.deg).to_value(u.rad)
-H_MAX_UPPER_LIMIT_M = 100_000
 
 
 def _far_outside_fov(fov_lat, fov_lon):
@@ -261,8 +260,7 @@ class HillasIntersection(HillasGeometryReconstructor):
         sky_pos = nom.transform_to(array_pointing.frame)
         tilt = SkyCoord(x=core_x * u.m, y=core_y * u.m, z=0 * u.m, frame=tilted_frame)
         grd = project_to_ground(tilt)
-
-        h_max = self.reconstruct_h_max(
+        x_max = self.reconstruct_xmax(
             nom.fov_lon,
             nom.fov_lat,
             tilt.x,
@@ -289,8 +287,8 @@ class HillasIntersection(HillasGeometryReconstructor):
             is_valid=True,
             alt_uncert=src_error.to(u.rad),
             az_uncert=src_error.to(u.rad),
-            h_max=h_max,
-            h_max_uncert=u.Quantity(np.nan * h_max.unit),
+            h_max=x_max,
+            h_max_uncert=u.Quantity(np.nan * x_max.unit),
             goodness_of_fit=np.nan,
             prefix=self.__class__.__name__,
         )
@@ -311,7 +309,7 @@ class HillasIntersection(HillasGeometryReconstructor):
 
         """
         if len(hillas_parameters) < 2:
-            return (np.nan, np.nan, np.nan, np.nan)  # Throw away events with < 2 images
+            return None  # Throw away events with < 2 images
 
         # Find all pairs of Hillas parameters
         combos = itertools.combinations(list(hillas_parameters.values()), 2)
@@ -383,8 +381,7 @@ class HillasIntersection(HillasGeometryReconstructor):
             core uncertainty X
         """
         if len(hillas_parameters) < 2:
-            return (np.nan, np.nan, np.nan, np.nan)  # Throw away events with < 2 images
-
+            return None  # Throw away events with < 2 images
         hill_list = list()
         tx = list()
         ty = list()
@@ -440,7 +437,7 @@ class HillasIntersection(HillasGeometryReconstructor):
 
         return x_pos, y_pos, np.sqrt(var_x), np.sqrt(var_y)
 
-    def reconstruct_h_max(
+    def reconstruct_xmax(
         self, source_x, source_y, core_x, core_y, hillas_parameters, tel_x, tel_y, zen
     ):
         """
@@ -498,19 +495,25 @@ class HillasIntersection(HillasGeometryReconstructor):
             np.array(ty),
         )
         weight = np.array(amp)
-        mean_distance = np.average(height, weights=weight)
+        mean_height = np.sum(height * weight) / np.sum(weight)
 
         # This value is height above telescope in the tilted system,
         # we should convert to height above ground
-        mean_height = mean_distance * np.cos(zen.to_value(u.rad))
+        mean_height *= np.cos(zen)
 
         # Add on the height of the detector above sea level
-        mean_height += self.subarray.reference_location.geodetic.height.to_value(u.m)
+        mean_height += 2100  # TODO: replace with instrument info
+
+        if mean_height > 100000 or np.isnan(mean_height):
+            mean_height = 100000
 
-        if mean_height > H_MAX_UPPER_LIMIT_M:
-            mean_height = np.nan
+        mean_height *= u.m
+        # Lookup this height in the depth tables, the convert Hmax to Xmax
+        # x_max = self.thickness_profile(mean_height.to(u.km))
+        # Convert to slant depth
+        # x_max /= np.cos(zen)
 
-        return u.Quantity(mean_height, u.m)
+        return mean_height
 
     @staticmethod
     def intersect_lines(xp1, yp1, phi1, xp2, yp2, phi2):
diff --git a/ctapipe/reco/hillas_reconstructor.py b/ctapipe/reco/hillas_reconstructor.py
index 0f82e2bc..1fbd305d 100644
--- a/ctapipe/reco/hillas_reconstructor.py
+++ b/ctapipe/reco/hillas_reconstructor.py
@@ -19,7 +19,6 @@ from ..coordinates import (
     altaz_to_righthanded_cartesian,
     project_to_ground,
 )
-from ..instrument import SubarrayDescription
 from .reconstructor import (
     HillasGeometryReconstructor,
     InvalidWidthException,
@@ -107,7 +106,7 @@ class HillasReconstructor(HillasGeometryReconstructor):
 
     """
 
-    def __init__(self, subarray: SubarrayDescription, **kwargs):
+    def __init__(self, subarray, **kwargs):
         super().__init__(subarray=subarray, **kwargs)
         _cam_radius_m = {
             cam: cam.geometry.guess_radius().to_value(u.m)
@@ -182,10 +181,7 @@ class HillasReconstructor(HillasGeometryReconstructor):
         _, lat, lon = cartesian_to_spherical(*direction)
 
         # estimate max height of shower
-        h_max = (
-            self.estimate_relative_h_max(cog_cartesian, telescope_positions)
-            + self.subarray.reference_location.geodetic.height
-        )
+        h_max = self.estimate_h_max(cog_cartesian, telescope_positions)
 
         # az is clockwise, lon counter-clockwise, make sure it stays in [0, 2pi)
         az = Longitude(-lon)
@@ -416,22 +412,18 @@ class HillasReconstructor(HillasGeometryReconstructor):
         return core_pos_ground, core_pos_tilted
 
     @staticmethod
-    def estimate_relative_h_max(cog_vectors, positions):
-        """Estimate the relative (to the observatory) vertical height of
-        shower-max by intersecting the lines of the cog directions of each
-        telescope.
+    def estimate_h_max(cog_vectors, positions):
+        """
+        Estimate the max height by intersecting the lines of the cog directions of each telescope.
 
         Returns
         -------
-        astropy.unit.Quantity:
-            the estimated height above observatory level (not sea level) of the
-            shower-max point
-
+        astropy.unit.Quantity
+            the estimated max height
         """
         positions = positions.cartesian.xyz.T.to_value(u.m)
-        shower_max = u.Quantity(
-            line_line_intersection_3d(cog_vectors, positions),
+        # not sure if its better to return the length of the vector of the z component
+        return u.Quantity(
+            np.linalg.norm(line_line_intersection_3d(cog_vectors, positions)),
             u.m,
         )
-
-        return shower_max[2]  # the z-coordinate only
diff --git a/ctapipe/tools/apply_models.py b/ctapipe/tools/apply_models.py
index 2df691d8..0a6285dc 100644
--- a/ctapipe/tools/apply_models.py
+++ b/ctapipe/tools/apply_models.py
@@ -177,13 +177,7 @@ class ApplyModels(Tool):
         for tel_id, table in tel_tables.items():
             tel = self.loader.subarray.tel[tel_id]
 
-            if len(table) == 0:
-                self.log.info("No events for telescope %d", tel_id)
-                continue
-
-            try:
-                predictions = reconstructor.predict_table(tel, table)
-            except KeyError:
+            if tel not in reconstructor._models:
                 self.log.warning(
                     "No model in %s for telescope type %s, skipping tel %d",
                     reconstructor,
@@ -192,6 +186,11 @@ class ApplyModels(Tool):
                 )
                 continue
 
+            if len(table) == 0:
+                self.log.info("No events for telescope %d", tel_id)
+                continue
+
+            predictions = reconstructor.predict_table(tel, table)
             for prop, prediction_table in predictions.items():
                 # copy/overwrite columns into full feature table
                 new_columns = prediction_table.colnames
diff --git a/docs/changes/2397.api.rst b/docs/changes/2397.api.rst
deleted file mode 100644
index 45b64781..00000000
--- a/docs/changes/2397.api.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-``CameraGeometry.position_to_pix_index`` will now return the minimum integer value for invalid
-pixel coordinates instead of -1 due to the danger of using -1 as an index in python accessing
-the last element of a data array for invalid pixels.
-The function will now also no longer raise an error if the arguments are empty arrays and instead
-just return an empty index array.
-The function will also no longer log a warning in case of coordinates that do not match a camera pixel.
-The function is very low-level and if not finding a pixel at the tested position warrants a warning or
-is expected will depend on the calling code.
diff --git a/docs/changes/2403.bugfix.rst b/docs/changes/2403.bugfix.rst
deleted file mode 100644
index 042b14c5..00000000
--- a/docs/changes/2403.bugfix.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-Fixed the definition of ``h_max``, which was both inconsistent between
-`~ctapipe.reco.HillasReconstructor` and `~ctapipe.reco.HillasIntersection`
-implementations, and was also incorrect since it was measured from the
-observatory elevation rather than from sea level.
-
-The value of ``h_max`` is now defined as the height above sea level of the
-shower-max point (in meters), not the distance to that point. Therefore it is
-not corrected for the zenith angle of the shower. This is consistent with the
-options currently used for *CORSIKA*, where the *SLANT* option is set to false,
-meaning heights are actual heights not distances from the impact point, and
-``x_max`` is a *depth*, not a *slant depth*. Note that this definition may be
-inconsistent with other observatories where slant-depths are used, and also note
-that the slant depth or distance to shower max are the more useful quantities
-for shower physics.
diff --git a/docs/changes/2411.features.rst b/docs/changes/2411.features.rst
deleted file mode 100644
index d81a88b9..00000000
--- a/docs/changes/2411.features.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-Add option ``override_obs_id`` to ``SimTelEventSource`` which allows
-assigning new, unique ``obs_ids`` in case productions re-use CORSIKA run
-numbers.
diff --git a/docs/changes/2418.bugfix.rst b/docs/changes/2418.bugfix.rst
deleted file mode 100644
index 5af5d6d3..00000000
--- a/docs/changes/2418.bugfix.rst
+++ /dev/null
@@ -1,1 +0,0 @@
-Do not use a hidden attribute of ``SKLearnReconstructor`` in ``ctapipe-apply-models``.
diff --git a/docs/conf.py b/docs/conf.py
index 5ae2d8c7..b91f6f0b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -290,6 +290,7 @@ html_theme_options = {
         "version_match": version_match,
         "json_url": json_url,
     },
+    "navigation_with_keys": False,
     "use_edit_page_button": True,
     "icon_links_label": "Quick Links",
     "icon_links": [


Test patch:
diff --git a/ctapipe/instrument/camera/tests/test_geometry.py b/ctapipe/instrument/camera/tests/test_geometry.py
index 8e3a7545..10410e0e 100644
--- a/ctapipe/instrument/camera/tests/test_geometry.py
+++ b/ctapipe/instrument/camera/tests/test_geometry.py
@@ -68,20 +68,10 @@ def test_load_lst_camera(prod5_lst):
 
 def test_position_to_pix_index(prod5_lst):
     """test that we can lookup a pixel from a coordinate"""
-    geometry = prod5_lst.camera.geometry
-
     x, y = (0.80 * u.m, 0.79 * u.m)
-
-    pix_id = geometry.position_to_pix_index(x, y)
-
+    pix_id = prod5_lst.camera.geometry.position_to_pix_index(x, y)
     assert pix_id == 1575
 
-    pix_ids = geometry.position_to_pix_index([0.8, 0.8] * u.m, [0.79, 0.79] * u.m)
-    np.testing.assert_array_equal(pix_ids, [1575, 1575])
-
-    assert len(geometry.position_to_pix_index([] * u.m, [] * u.m)) == 0
-    assert geometry.position_to_pix_index(5 * u.m, 5 * u.m) == np.iinfo(int).min
-
 
 def test_find_neighbor_pixels():
     """test basic neighbor functionality"""
diff --git a/ctapipe/io/tests/test_simteleventsource.py b/ctapipe/io/tests/test_simteleventsource.py
index 116a8a91..b4d3c005 100644
--- a/ctapipe/io/tests/test_simteleventsource.py
+++ b/ctapipe/io/tests/test_simteleventsource.py
@@ -604,25 +604,3 @@ def test_starting_grammage():
     with SimTelEventSource(path, focal_length_choice="EQUIVALENT") as source:
         e = next(iter(source))
         assert e.simulation.shower.starting_grammage == 580 * u.g / u.cm**2
-
-
-@pytest.mark.parametrize("override_obs_id,expected_obs_id", [(None, 1), (5, 5)])
-def test_override_obs_id(override_obs_id, expected_obs_id, prod5_gamma_simtel_path):
-    """Test for the override_obs_id option"""
-    original_run_number = 1
-
-    with SimTelEventSource(
-        prod5_gamma_simtel_path, override_obs_id=override_obs_id
-    ) as s:
-        assert s.obs_id == expected_obs_id
-        assert s.obs_ids == [expected_obs_id]
-
-        assert s.simulation_config.keys() == {expected_obs_id}
-        assert s.observation_blocks.keys() == {expected_obs_id}
-        assert s.scheduling_blocks.keys() == {expected_obs_id}
-
-        # this should alway be the original run number
-        assert s.simulation_config[s.obs_id].run_number == original_run_number
-
-        for e in s:
-            assert e.index.obs_id == expected_obs_id
diff --git a/ctapipe/reco/tests/test_HillasReconstructor.py b/ctapipe/reco/tests/test_HillasReconstructor.py
index fd8ca438..9fe7c57d 100644
--- a/ctapipe/reco/tests/test_HillasReconstructor.py
+++ b/ctapipe/reco/tests/test_HillasReconstructor.py
@@ -44,9 +44,12 @@ def test_h_max_results():
     )
 
     cog_cart = altaz_to_righthanded_cartesian(cog_alt, cog_az)
-    h_max_reco = HillasReconstructor.estimate_relative_h_max(
-        cog_vectors=cog_cart, positions=positions
-    )
+
+    # creating the fit class and setting the the great circle member
+
+    # performing the direction fit with the minimisation algorithm
+    # and a seed that is perpendicular to the up direction
+    h_max_reco = HillasReconstructor.estimate_h_max(cog_cart, positions)
 
     # the results should be close to the direction straight up
     assert u.isclose(h_max_reco, 1 * u.km)
@@ -207,6 +210,7 @@ def test_reconstruction_against_simulation_camera_frame(
     ],
 )
 def test_CameraFrame_against_TelescopeFrame(filename):
+
     input_file = get_dataset_path(filename)
     # "gamma_divergent_LaPalma_baseline_20Zd_180Az_prod3_test.simtel.gz"
     # )
@@ -239,6 +243,7 @@ def test_CameraFrame_against_TelescopeFrame(filename):
     reconstructed_events = 0
 
     for event_telescope_frame in source:
+
         calib(event_telescope_frame)
         # make a copy of the calibrated event for the camera frame case
         # later we clean and paramretrize the 2 events in the same way
@@ -276,6 +281,7 @@ def test_CameraFrame_against_TelescopeFrame(filename):
                 elif isinstance(cam, list):
                     assert cam == tel
                 else:
+
                     if cam == 0 or tel == 0:
                         kwargs["atol"] = 1e-6
                     assert np.isclose(cam, tel, **kwargs)
diff --git a/ctapipe/reco/tests/test_hillas_intersection.py b/ctapipe/reco/tests/test_hillas_intersection.py
index 924699b7..94492aba 100644
--- a/ctapipe/reco/tests/test_hillas_intersection.py
+++ b/ctapipe/reco/tests/test_hillas_intersection.py
@@ -30,8 +30,8 @@ def test_intersect():
 
 def test_parallel():
     """
-    ?    Simple test to check the intersection of lines. Try to intersect positions at (0,0) and (0,1)
-        with angles parallel and check the behaviour
+    Simple test to check the intersection of lines. Try to intersect positions at (0,0) and (0,1)
+    with angles parallel and check the behaviour
     """
     x1 = 0
     y1 = 0
@@ -83,7 +83,7 @@ def test_intersection_xmax_reco(example_subarray):
         ),
     }
 
-    h_max = hill_inter.reconstruct_h_max(
+    x_max = hill_inter.reconstruct_xmax(
         source_x=nom_pos_reco.fov_lon,
         source_y=nom_pos_reco.fov_lat,
         core_x=0 * u.m,
@@ -93,8 +93,7 @@ def test_intersection_xmax_reco(example_subarray):
         tel_y={1: (0 * u.m), 2: (150 * u.m)},
         zen=zen_pointing,
     )
-
-    assert h_max > 0 * u.m
+    print(x_max)
 
 
 def test_intersection_reco_impact_point_tilted(example_subarray):