Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5845e78
feat: Implement true_disp calculation in ctapipe-process + test
koopatroopa787 Feb 17, 2026
d775870
docs: Add changelog fragment for #2950
koopatroopa787 Feb 17, 2026
bea9764
refactor: Use single true_disp field and shared calculation utility
koopatroopa787 Feb 17, 2026
7ed8dec
Refactor true_disp: Move to SimulatedCameraContainer, use shared util…
koopatroopa787 Feb 17, 2026
db1e5ac
feat: Calculate true_disp and fix writer bugs
koopatroopa787 Feb 25, 2026
348f76e
fix: Robust HDF5TableWriter handling for metadata and rows
koopatroopa787 Feb 25, 2026
2f6f3ce
fix: Import Container in tableio.py and finalize writer robustness
koopatroopa787 Feb 25, 2026
2bb287f
add lazy property with telescope coordinates as EarthLocation
mexanick Feb 13, 2026
928abe1
add changelog
mexanick Feb 13, 2026
1b013b5
Fix changelog
mexanick Feb 13, 2026
df21fae
Improve developer setup instructions in Getting Started guide
yaochengchen Feb 16, 2026
dc000e4
add changelog
yaochengchen Feb 16, 2026
035297a
update as reviewer's suggestion
yaochengchen Feb 17, 2026
fba4463
Fix trigger check in HDF5EventSource.is_compatible
yaochengchen Feb 16, 2026
9d9e010
add changelog
yaochengchen Feb 16, 2026
aa32c83
Fix typos in hillas_reconstructor.py
yaochengchen Feb 24, 2026
b157186
Fix a typo in README.md
yaochengchen Feb 24, 2026
6bb1777
Add changelog
yaochengchen Feb 24, 2026
66a2994
Fix a typo in README.rst
yaochengchen Feb 24, 2026
b44a018
Fix a typo in README.rst
yaochengchen Feb 24, 2026
bd7e32c
Fix a typo in README.rst
yaochengchen Feb 24, 2026
d1dc7aa
Fix a typo in hillas.py
yaochengchen Feb 24, 2026
8eeedd3
Modify changelog
yaochengchen Feb 24, 2026
37603e8
Update src/ctapipe/image/hillas.py
yaochengchen Feb 24, 2026
ccc3c6d
Update README.rst
yaochengchen Feb 24, 2026
43188e7
Fix missing example blocks in trigger doc
maxnoe Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Low-level data processing pipeline software for the
`CTAO (Cherenkov Telescope Array Observatory) <https://www.ctao.org>`__.

This is code is a prototype data processing framework and is under rapid
This code is a prototype data processing framework and is under rapid
development. It is not recommended for production use unless you are an
expert or developer!

Expand All @@ -39,7 +39,7 @@ You can find all ctapipe Zenodo records here: `List of ctapipe Records on Zenodo

There is also a Zenodo DOI always pointing to the latest version: |doilatest|

At this point, our latest publication is the `2023 ICRC proceeding <https://doi.org/10.22323/1.444.0703>`_, which you can
At this point, the latest publication is our contribution in the `2023 ICRC proceedings <https://doi.org/10.22323/1.444.0703>`_, which you can
cite using this bibtex entry:

.. code::
Expand Down Expand Up @@ -74,11 +74,11 @@ or via::

pip install ctapipe

**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**: to install a specific version of ctapipe take a 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).
Note that 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.io/en/latest/developer-guide/getting-started.html>`__.
1 change: 1 addition & 0 deletions docs/changes/2947.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added ``tel_earth_locations`` lazy property to ``SubarrayDescription`` that caches telescope positions as ``EarthLocation`` objects.
1 change: 1 addition & 0 deletions docs/changes/2948.maintenance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve clarity and correctness of the Getting Started developer guide, fixing typos, outdated Git commands, and inconsistent terminology.
4 changes: 4 additions & 0 deletions docs/changes/2949.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fixed incorrect trigger compatibility check in ``HDF5EventSource.is_compatible``.

``has_trigger`` was mistakenly checking ``SIMULATION_TEL_TABLE`` due to a
copy-paste error. It now correctly checks for the presence of DL1 trigger tables.
1 change: 1 addition & 0 deletions docs/changes/2950.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement calculation of ``true_disp`` parameters (norm and sign) in ``ctapipe-process`` for simulated events.
1 change: 1 addition & 0 deletions docs/changes/2956.maintenance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix typos in ``README.rst`` and ``ctapipe.image.hillas.py``.
1 change: 1 addition & 0 deletions docs/changes/2957.maintenance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix typos in ``ctapipe.reco.hillas_reconstructor``.
24 changes: 13 additions & 11 deletions docs/developer-guide/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ We strongly recommend using the `mambaforge conda distribution <https://github.c
The following guide is used only if you want to *develop* the
``ctapipe`` package, if you just want to write code that uses it
as a dependency, you can install ``ctapipe`` from PyPI or conda-forge.
See :ref:`getting_started_users`
See :ref:`getting_started_users`.


Forking vs. Working in the Main Repository
Expand Down Expand Up @@ -60,7 +60,7 @@ See `the GitHub documentation <https://docs.github.com/en/authentication/connect
having write access to the main repository at ``cta-observatory/ctapipe``, you
`need to fork <https://help.github.com/articles/fork-a-repo/>`_ it.

After that, clone your fork of the repository and add the main reposiory as a second
After that, clone your fork of the repository and add the main repository as a second
remote called ``upstream``, so that you can keep your fork synchronized with the main repository.

.. code-block:: console
Expand Down Expand Up @@ -93,7 +93,7 @@ terminal to activate the conda environment.
Installing ctapipe in Development Mode
======================================

Now setup this cloned version for development.
Now set up this cloned version for development.
The following command will use the editable installation feature of python packages.
From then on, all the ctapipe executables and the library itself will be
usable from anywhere, given you have activated the ``cta-dev`` conda environment.
Expand All @@ -116,7 +116,7 @@ test plugin via
$ pip install -e ./test_plugin


We are using the ``pre-commit``, ``code-spell`` and ``ruff`` tools
We are using the ``pre-commit``, ``codespell`` and ``ruff`` tools
for automatic adherence to the code style
(see our :doc:`/developer-guide/style-guide`).
To enforce running these tools whenever you make a commit, setup the
Expand All @@ -128,7 +128,7 @@ To enforce running these tools whenever you make a commit, setup the

The pre-commit hook will then execute the tools with the same settings as when a pull request is checked on GitHub,
and if any problems are reported the commit will be rejected.
You then have to fix the reported issues before tying to commit again.
You then have to fix the reported issues before trying to commit again.
Note that a common problem is code not complying with the style guide, and that whenever this was the only problem found,
simply adding the changes resulting from the pre-commit hook to the commit will result in your changes being accepted.

Expand Down Expand Up @@ -200,7 +200,7 @@ to keep forks in sync.

Remember that ``git switch <name>`` [#switch]_ switches between branches,
``git switch -c <name>`` creates a new branch and switches to it,
and ``git branch`` on it's own will tell you which branches are available
and ``git branch`` on its own will tell you which branches are available
and which one you are currently on.


Expand Down Expand Up @@ -267,8 +267,8 @@ sub-module), check the style, and make sure the docs render correctly
(e.g it should not mix changes that are logically different).
Therefore it's best to group related changes with ``git
add <files>``. You may even commit only *parts* of a changed file
using and ``git add -p``. If you want to keep your git commit
history clean, learn to use commands like ``git commit --ammend``
using ``git add -p``. If you want to keep your git commit
history clean, learn to use commands like ``git commit --amend``
(append to previous commit without creating a new one, e.g. when
you find a typo or something small).

Expand Down Expand Up @@ -358,7 +358,7 @@ For differences between rebasing and merging and when to use which, see `this tu
Create a *Pull Request*
-----------------------

When you're happy, you create PR on on your github fork page by clicking
When you're happy, you create a PR on your GitHub fork page by clicking
"pull request". You can also do this via *GitHub Desktop* if you have
that installed, by pushing the pull-request button in the
upper-right-hand corner.
Expand Down Expand Up @@ -402,7 +402,7 @@ since it is no longer needed (assuming it was accepted and merged in):

.. code-block:: console

$ git switch main # switch back to your master branch
$ git switch main # switch back to your main branch

pull in the upstream changes, which should include your new features, and
remove the branch from the local and remote (github).
Expand All @@ -428,7 +428,9 @@ And then delete your branch:

.. code-block:: console

$ git branch --delete --remotes implement_feature_1
$ git push origin --delete implement_feature_1
$ git pull
$ git fetch --prune


Debugging Your Code
Expand Down
47 changes: 47 additions & 0 deletions scripts/deploy.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@echo off
set SERVER_IP=159.65.61.54
set ZIP_FILE=ctapipe_deploy.zip

REM Automatically change to the project root (parent directory of this script)
cd /d "%~dp0.."

echo Running from: %CD%
echo Packaging code for deployment...

rem Create a temporary deployment directory if it doesn't exist
if not exist "deploy" mkdir deploy

rem Copy source code
if exist "src" (
echo Copying src...
xcopy /E /I /Y src deploy\src
)

rem Copy documentation
if exist "docs" (
echo Copying docs...
xcopy /E /I /Y docs deploy\docs
)

rem Copy examples
if exist "examples" (
echo Copying examples...
xcopy /E /I /Y examples deploy\examples
)

rem Copy setup files
if exist "pyproject.toml" copy pyproject.toml deploy\
if exist "setup.cfg" copy setup.cfg deploy\
if exist "setup.py" copy setup.py deploy\
if exist "README.md" copy README.md deploy\
if exist "LICENSE" copy LICENSE deploy\

echo.
echo Deployment package created in the 'deploy' directory.
echo To move to Linux server, use scp or similar:
echo scp -r deploy/* user@linux-server:/path/to/ctapipe/
echo.
echo NOTE: Ensure you have installed dependencies on the Linux server:
echo pip install -e .[all]
echo.
pause
6 changes: 6 additions & 0 deletions src/ctapipe/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,12 @@ class SimulatedCameraContainer(Container):
description="true impact parameter",
)

true_disp = Field(
nan * u.deg,
description="True disp parameter",
unit=u.deg,
)


class SimulatedEventContainer(Container):
shower = Field(
Expand Down
2 changes: 2 additions & 0 deletions src/ctapipe/core/traits.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ def _validate_str(self, obj, value):
value = get_dataset_path(value.partition("dataset://")[2])
elif url.scheme in ("", "file"):
value = pathlib.Path(url.netloc, url.path)
elif os.name == "nt" and len(url.scheme) == 1:
value = pathlib.Path(value)
else:
self.error(obj, value)

Expand Down
2 changes: 1 addition & 1 deletion src/ctapipe/image/hillas.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def hillas_parameters(geom, image):
The recommended form is to pass only the sliced geometry and image
for the pixels to be considered.

Each method gives the same result, but vary in efficiency
The method also supports giving a full geometry with image as a masked array, however this performs worse than passing geometry and image only for the selected pixels.

Parameters
----------
Expand Down
35 changes: 34 additions & 1 deletion src/ctapipe/image/image_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ def _process_telescope_event(self, event):
peak_time=None, # true image from simulation has no peak time
default=DEFAULT_TRUE_IMAGE_PARAMETERS,
)
from ctapipe.core import Container

for container in sim_camera.true_parameters.values():
if not container.prefix.startswith("true_"):
if isinstance(container, Container) and not container.prefix.startswith("true_"):
container.prefix = f"true_{container.prefix}"

self.log.debug(
Expand All @@ -261,3 +263,34 @@ def _process_telescope_event(self, event):
recursive=True
),
)

if (
dl1_camera.parameters.hillas is not None
and np.isfinite(dl1_camera.parameters.hillas.fov_lat)
and np.isfinite(dl1_camera.parameters.hillas.fov_lon)
):
pointing = event.monitoring.tel[tel_id].pointing
shower = event.simulation.shower

from ctapipe.reco.preprocessing import (
horizontal_to_telescope,
calculate_true_disp,
)

fov_lon, fov_lat = horizontal_to_telescope(
alt=shower.alt,
az=shower.az,
pointing_alt=pointing.altitude,
pointing_az=pointing.azimuth,
)

hillas = dl1_camera.parameters.hillas

sim_camera.true_disp = calculate_true_disp(
fov_lon=fov_lon,
fov_lat=fov_lat,
hillas_psi=hillas.psi,
hillas_lon=hillas.fov_lon,
hillas_lat=hillas.fov_lat,
)

16 changes: 16 additions & 0 deletions src/ctapipe/instrument/subarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ def tel_coords(self):

return SkyCoord(x=pos_x, y=pos_y, z=pos_z, unit=u.m, frame=frame)

@lazyproperty
def tel_earth_locations(self):
"""
Telescope positions as `~astropy.coordinates.EarthLocation` objects.

Returns
-------
dict[int, EarthLocation]
Dictionary mapping telescope IDs to their EarthLocation.
This is cached to avoid expensive repeated conversions.
"""
return {
tel_id: coord.to_earth_location()
for tel_id, coord in zip(self.tel_ids, self.tel_coords)
}

@lazyproperty
def tel_ids(self):
"""Array of telescope ids in order of telescope indices"""
Expand Down
27 changes: 27 additions & 0 deletions src/ctapipe/instrument/tests/test_subarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,30 @@ def test_check_matchings_subarray(example_subarray, subarray_prod5_paranal):
assert not SubarrayDescription.check_matching_subarrays(
[example_subarray, subarray_prod5_paranal]
)


def test_tel_earth_locations(example_subarray):
"""Test cached tel_earth_locations property"""
# Get the cached property
earth_locs = example_subarray.tel_earth_locations

assert isinstance(earth_locs, dict)
assert len(earth_locs) == example_subarray.n_tels

# Check all telescope IDs are present
for tel_id in example_subarray.tel_ids:
assert tel_id in earth_locs
assert isinstance(earth_locs[tel_id], EarthLocation)

# Verify conversion is correct by comparing with manual conversion
tel_id = example_subarray.tel_ids[0]
tel_index = example_subarray.tel_index_array[tel_id]
manual_location = example_subarray.tel_coords[tel_index].to_earth_location()

assert u.isclose(earth_locs[tel_id].x, manual_location.x)
assert u.isclose(earth_locs[tel_id].y, manual_location.y)
assert u.isclose(earth_locs[tel_id].z, manual_location.z)

# Verify it's cached (same object returned)
earth_locs_2 = example_subarray.tel_earth_locations
assert earth_locs is earth_locs_2
22 changes: 12 additions & 10 deletions src/ctapipe/instrument/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,22 @@ class SoftwareTrigger(TelescopeComponent):
With the default settings, this class is a no-op. To get the correct behavior
for CTA simulations, use the following configuration:

..
SoftwareTrigger:
min_telescopes: 2
min_telescopes_of_type:
- ["type", "*", 0]
- ["type", "LST*", 2]
.. code-block:: yaml

SoftwareTrigger:
min_telescopes: 2
min_telescopes_of_type:
- ["type", "*", 0]
- ["type", "LST*", 2]

With this class it is also possible to filter for specific telescope event types,
e.g. to analyze the RANDOM_MONO or MUON tagged telescope events in isolation:

..
SoftwareTrigger:
allowed_telescope_event_types:
- "RANDOM_MONO"
.. code-block:: yaml

SoftwareTrigger:
allowed_telescope_event_types:
- "RANDOM_MONO"
"""

min_telescopes = Integer(
Expand Down
1 change: 1 addition & 0 deletions src/ctapipe/io/datawriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ def _write_dl1_telescope_events(self, event: ArrayEventContainer):
true_parameters.concentration,
true_parameters.morphology,
true_parameters.intensity_statistics,
event.simulation.tel[tel_id].true_disp,
],
)

Expand Down
4 changes: 3 additions & 1 deletion src/ctapipe/io/hdf5eventsource.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,9 @@ def is_compatible(file_path):
# we can now read both R1 and DL1
has_muons = DL1_TEL_MUON_GROUP in f.root
has_sim = SIMULATION_TEL_TABLE in f.root
has_trigger = SIMULATION_TEL_TABLE in f.root
has_trigger = (DL1_SUBARRAY_TRIGGER_TABLE in f) or (
DL1_TEL_TRIGGER_TABLE in f
)

datalevels = set(metadata["CTA PRODUCT DATA LEVELS"].split(","))
datalevels = (
Expand Down
Loading