Repository: cta-observatory/ctapipe (python)

Issue:
recent ctapipe-process crashes on public MC files
**Describe the bug**
ctapipe-process crashes when running on the [public MC files](https://zenodo.org/records/7298569)

**To Reproduce**
`ctapipe-process --input PublicMC/gamma-diffuse_with_images_00.dl2.h5`

**Expected behavior**
That a dl2 level file is produced.

**Supporting information**
```
2024-10-24 00:38:56,988 ERROR [ctapipe.ctapipe-process] (tool.run): Caught unexpected exception: 'NoneType' object has no attribute 'geodetic'
Traceback (most recent call last):
  File "/local/home/tb273079/DataPipe/ctapipe-dev/src/ctapipe/core/tool.py", line 431, in run
    self.start()
  File "/local/home/tb273079/DataPipe/ctapipe-dev/src/ctapipe/tools/process.py", line 294, in start
    self.event_source.subarray.info(printer=self.log.info)
  File "/local/home/tb273079/DataPipe/ctapipe-dev/src/ctapipe/instrument/subarray.py", line 130, in info
    printer(f"Height   : {self.reference_location.geodetic.height:.2f}")
```

**Additional context**
Add any other context about the problem here.


Pull request description:
Set null island as fallback reference location in Subarray.from_hdf
fixes #2626

Patch:
diff --git a/docs/changes/2627.bugfix.rst b/docs/changes/2627.bugfix.rst
new file mode 100644
index 00000000..4ed358e1
--- /dev/null
+++ b/docs/changes/2627.bugfix.rst
@@ -0,0 +1,6 @@
+Fix that hdf5 files created with older versions of ctapipe, e.g.
+the public dataset created with 0.17 can be read by ctapipe-process.
+These files are missing the subarray reference location, which was
+introduced in later versions of ctapipe. A dummy location (lon=0, lat=0)
+is used for these now, the same value is already used for simtel files
+lacking this information.
diff --git a/src/ctapipe/instrument/subarray.py b/src/ctapipe/instrument/subarray.py
index e69e34f7..eafd56c2 100644
--- a/src/ctapipe/instrument/subarray.py
+++ b/src/ctapipe/instrument/subarray.py
@@ -751,7 +751,6 @@ class SubarrayDescription:
 
         positions = np.column_stack([layout[f"pos_{c}"] for c in "xyz"])
 
-        reference_location = None
         name = layout.meta.get("SUBARRAY", "Unknown")
 
         if "reference_itrs_x" in layout.meta:
@@ -760,6 +759,13 @@ class SubarrayDescription:
                 y=layout.meta["reference_itrs_y"] * u.m,
                 z=layout.meta["reference_itrs_z"] * u.m,
             )
+        else:
+            # "null island" dummy location for backwards compatibility with old files
+            reference_location = EarthLocation(
+                lon=0 * u.deg,
+                lat=0 * u.deg,
+                height=0 * u.m,
+            )
 
         return cls(
             name=str(name),


Test patch:
diff --git a/src/ctapipe/tools/tests/test_process.py b/src/ctapipe/tools/tests/test_process.py
index 769574c7..17ba5ae8 100644
--- a/src/ctapipe/tools/tests/test_process.py
+++ b/src/ctapipe/tools/tests/test_process.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-
 """
 Test ctapipe-process on a few different use cases
 """
@@ -488,3 +487,31 @@ def test_only_trigger_and_simulation(tmp_path):
         assert len(events) == 7
         assert "tels_with_trigger" in events.colnames
         assert "true_energy" in events.colnames
+
+
+@pytest.mark.parametrize(
+    ("input_url", "args"),
+    [
+        pytest.param(
+            "dataset://gamma_diffuse_dl2_train_small.dl2.h5",
+            ["--no-write-images", "--max-events=5"],
+            id="0.17",
+        )
+    ],
+)
+def test_on_old_file(input_url, args, tmp_path):
+    config = resource_file("stage1_config.json")
+
+    output_path = tmp_path / "test.dl1.h5"
+    run_tool(
+        ProcessorTool(),
+        argv=[
+            f"--config={config}",
+            f"--input={input_url}",
+            f"--output={output_path}",
+            "--overwrite",
+            *args,
+        ],
+        cwd=tmp_path,
+        raises=True,
+    )