Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions docs/changes/1938.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Rename simtools-calculate-incident-angles to simtools-derive-incident-angle, add histogram calculation and writing functionality and output metadata.
2 changes: 1 addition & 1 deletion docs/source/user-guide/applications.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ Parameters with the same functionality are named consistently the same among all
:glob: true
:maxdepth: 1

simtools-calculate-incident-angles <applications/simtools-calculate-incident-angles>
simtools-convert-all-model-parameters-from-simtel <applications/simtools-convert-all-model-parameters-from-simtel>
simtools-convert-geo-coordinates-of-array-elements <applications/simtools-convert-geo-coordinates-of-array-elements>
simtools-convert-model-parameter-from-simtel <applications/simtools-convert-model-parameter-from-simtel>
Expand All @@ -63,6 +62,7 @@ simtools-db-generate-compound-indexes <applications/simtools-db-generate-compoun
simtools-db-inspect-databases <applications/simtools-db-inspect-databases>
simtools-db-upload-model-repository <applications/simtools-db-upload-model-repository>
simtools-derive-ctao-array-layouts <applications/simtools-derive-ctao-array-layouts>
simtools-derive-incident-angle <applications/simtools-derive-incident-angle>
simtools-derive-mirror-rnda <applications/simtools-derive-mirror-rnda>
simtools-derive-photon-electron-spectrum <applications/simtools-derive-photon-electron-spectrum>
simtools-derive-pulse-shape-parameters <applications/simtools-derive-pulse-shape-parameters>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
simtools-derive-incident-angle
==============================

.. automodule:: simtools.applications.derive_incident_angle
:members:
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ optional-dependencies."tests" = [
urls."bug tracker" = "https://github.com/gammasim/simtools/issues"
urls."documentation" = "https://gammasim.github.io/simtools/"
urls."repository" = "https://github.com/gammasim/simtools"
scripts.simtools-calculate-incident-angles = "simtools.applications.calculate_incident_angles:main"
scripts.simtools-convert-all-model-parameters-from-simtel = "simtools.applications.convert_all_model_parameters_from_simtel:main"
scripts.simtools-convert-geo-coordinates-of-array-elements = "simtools.applications.convert_geo_coordinates_of_array_elements:main"
scripts.simtools-convert-model-parameter-from-simtel = "simtools.applications.convert_model_parameter_from_simtel:main"
Expand All @@ -87,6 +86,7 @@ scripts.simtools-db-get-parameter-from-db = "simtools.applications.db_get_parame
scripts.simtools-db-inspect-databases = "simtools.applications.db_inspect_databases:main"
scripts.simtools-db-upload-model-repository = "simtools.applications.db_upload_model_repository:main"
scripts.simtools-derive-ctao-array-layouts = "simtools.applications.derive_ctao_array_layouts:main"
scripts.simtools-derive-incident-angle = "simtools.applications.derive_incident_angle:main"
scripts.simtools-derive-mirror-rnda = "simtools.applications.derive_mirror_rnda:main"
scripts.simtools-derive-photon-electron-spectrum = "simtools.applications.derive_photon_electron_spectrum:main"
scripts.simtools-derive-psf-parameters = "simtools.applications.derive_psf_parameters:main"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
r"""
Calculate photon incident angles on focal plane and primary/secondary mirrors.
Derive photon incident angles on focal plane and primary/secondary mirrors.

Creates photon files with additional columns for incident angles calculation.
Outputs files and histograms of the incidence angles at
Expand All @@ -14,7 +14,7 @@

.. code-block:: console

simtools-calculate-incident-angles \
simtools-derive-incident-angle \
--off_axis_angles 0 1 2 3 4 \
--source_distance 10 \
--number_of_photons 1000000 \
Expand Down Expand Up @@ -47,27 +47,27 @@

Example of a focal-plane incident angle plot for a SST:

.. _plot_calculate_incident_angles_plot:
.. image:: images/incident_angles_multi_calculate_incident_angles_SSTS-04.png
.. _plot_derive_incident_angle_plot:
.. image:: images/incident_angles_multi_derive_incident_angle_SSTS-04.png
:width: 49 %

Example of a primary mirror incident angle plot for a SST:

.. _plot_calculate_incident_angles_plot_primary:
.. image:: images/incident_angles_primary_multi_calculate_incident_angles_SSTS-04.png
.. _plot_derive_incident_angle_plot_primary:
.. image:: images/incident_angles_primary_multi_derive_incident_angle_SSTS-04.png
:width: 49 %

Note also the relation between radius and primary mirror incident angles, and how this relates to
the peak seen in the primary mirror incident angle distribution:

.. _plot_calculate_incident_angles_plot_angle_vs_radius:
.. _plot_derive_incident_angle_plot_angle_vs_radius:
.. image:: images/primary_angle_vs_radius.png
:width: 49 %

Example of a secondary mirror incident angle plot for a SST:

.. _plot_calculate_incident_angles_plot_secondary:
.. image:: images/incident_angles_secondary_multi_calculate_incident_angles_SSTS-04.png
.. _plot_derive_incident_angle_plot_secondary:
.. image:: images/incident_angles_secondary_multi_derive_incident_angle_SSTS-04.png
:width: 49 %
"""

Expand All @@ -82,9 +82,7 @@ def _parse():
"""Parse command line configuration."""
config = configurator.Configurator(
label=get_application_label(__file__),
description=(
"Calculate photon incident angles on focal plane and primary/secondary mirrors."
),
description=("Derive photon incident angles on focal plane and primary/secondary mirrors."),
)
config.parser.add_argument(
"--off_axis_angles",
Expand Down Expand Up @@ -123,7 +121,7 @@ def _parse():
config.parser.add_argument(
"--calculate_primary_secondary_angles",
dest="calculate_primary_secondary_angles",
help="Also compute angles of incidence on primary and secondary mirrors",
help="Compute angles of incidence on primary and secondary mirrors",
required=False,
action="store_true",
)
Expand All @@ -134,10 +132,10 @@ def _parse():


def main():
"""Calculate photon incident angles on focal plane and primary/secondary mirrors."""
"""Derive photon incident angles on focal plane and primary/secondary mirrors."""
app_context = startup_application(_parse)

app_context.logger.info("Starting calculation of incident angles")
app_context.logger.info("Starting derivation of incident angles")

output_dir = app_context.io_handler.get_output_directory()
base_label = app_context.args.get("label", get_application_label(__file__))
Expand All @@ -158,9 +156,10 @@ def main():
label_with_telescope,
debug_plots=app_context.args.get("debug_plots", False),
)
calculator.save_model_parameters(results_by_offset)
total = sum(len(t) for t in results_by_offset.values())
summary_msg = (
f"Calculated incident angles for {len(results_by_offset)} offsets,\n"
f"Derived incident angles for {len(results_by_offset)} offsets,\n"
f"total photon statistics {total}"
)
if total < 1_000_000:
Expand Down
91 changes: 88 additions & 3 deletions src/simtools/ray_tracing/incident_angles.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
from pathlib import Path

import astropy.units as u
from astropy.table import QTable
import numpy as np
from astropy.table import QTable, vstack

from simtools import settings
from simtools.data_model.metadata_collector import MetadataCollector
from simtools.data_model.model_data_writer import ModelDataWriter
from simtools.model.model_utils import initialize_simulation_models


Expand Down Expand Up @@ -283,7 +285,7 @@ def _compute_incidence_angles_from_imaging_list(self, photons_file):
Column positions may differ between telescope types and sim_telarray versions.
Header lines (``# Column N: ...``) are parsed to find indices; otherwise
legacy positions (1-based) are used: focal=26, primary=32, secondary=36,
primary X/Y = 29/30, secondary X/Y = 33/34.
primary X/Y = 29/30, secondary X/Y=33/34.

Parameters
----------
Expand Down Expand Up @@ -692,9 +694,92 @@ def _save_results(self):
self.logger.warning("No results to save")
return
output_file = self.results_dir / f"incident_angles_{self._label_suffix()}.ecsv"
self.results.write(output_file, format="ascii.ecsv", overwrite=True)

data = self.results["angle_incidence_focal"].to(u.deg).value
bin_centers, hist = self._calculate_histogram(data, bins=1000)

output_table = QTable()
output_table["Incidence angle"] = bin_centers * u.deg
output_table["Fraction"] = hist

output_table.write(output_file, format="ascii.ecsv", overwrite=True)

MetadataCollector.dump(
args_dict=self.config_data,
output_file=output_file.with_suffix(".yml"),
)

def save_model_parameters(self, results_by_offset):
"""
Write model parameters dictionary (json) + astropy table with incident angles.

Parameters
----------
results_by_offset : dict
Dictionary with results for each offset.
"""
# Combine results from all offsets
tables = [res for res in results_by_offset.values() if res is not None and len(res) > 0]
if not tables:
self.logger.warning("No results to write model parameters.")
return

combined_table = vstack(tables)

parameter_mapping = {
"camera_filter_incidence_angle": "angle_incidence_focal",
"primary_mirror_incidence_angle": "angle_incidence_primary",
"secondary_mirror_incidence_angle": "angle_incidence_secondary",
}

for param_name, col_name in parameter_mapping.items():
if col_name not in combined_table.colnames:
continue

data = combined_table[col_name].to(u.deg).value
# Create histogram
bin_centers, hist = self._calculate_histogram(data, bins=100)

table = QTable()
table["Incidence angle"] = bin_centers * u.deg
table["Fraction"] = hist

writer = ModelDataWriter(
product_data_file=self.output_dir / f"{param_name}.ecsv",
product_data_format="ecsv",
args_dict=self.config_data,
)
writer.write(
product_data=table,
metadata=MetadataCollector(args_dict=self.config_data),
)

ModelDataWriter.dump_model_parameter(
parameter_name=param_name,
value=f"{param_name}.ecsv",
instrument=self.config_data["telescope"],
parameter_version=self.config_data["model_version"],
output_file=f"{param_name}.json",
output_path=self.output_dir,
metadata_input_dict=self.config_data,
)

def _calculate_histogram(self, data, bins=100):
"""
Calculate normalized histogram (density).

Parameters
----------
data : numpy.ndarray
Data to calculate histogram for.
bins : int
Number of bins.

Returns
-------
tuple
Bin centers and histogram values (density).
"""
hist, bin_edges = np.histogram(data, bins=bins, density=True)
bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
return bin_centers, hist

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
applications:
- application: simtools-calculate-incident-angles
- application: simtools-derive-incident-angle
configuration:
site: South
telescope: SSTS-01
Expand All @@ -9,9 +9,9 @@ applications:
model_version: 6.0.2
output_path: simtools-output
integration_tests:
- output_file: incident_angles/incident_angles_calculate_incident_angles_SSTS-01_off1.ecsv
- output_file: plots/incident_angles_multi_calculate_incident_angles_SSTS-01.png
- output_file: logs/incident_angles_calculate_incident_angles_SSTS-01_off1.log
- output_file: incident_angles/incident_angles_derive_incident_angle_SSTS-01_off1.ecsv
- output_file: plots/incident_angles_multi_derive_incident_angle_SSTS-01.png
- output_file: logs/incident_angles_derive_incident_angle_SSTS-01_off1.log
test_name: incident_angles_dual_mirror
schema_name: application_workflow.metaschema
schema_version: 0.4.0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was wondering if we want to have one of the integration tests with several off_axis_angles?

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
applications:
- application: simtools-derive-incident-angle
configuration:
site: South
telescope: SSTS-01
off_axis_angles: 1.0
number_of_photons: 10000
model_version: 6.0.2
output_path: simtools-output
debug_plots: true
calculate_primary_secondary_angles: true
integration_tests:
- output_file: incident_angles/incident_angles_derive_incident_angle_SSTS-01_off1.ecsv
- output_file: plots/incident_angles_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_angles_primary_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_secondary_xy_heatmap_off1_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_primary_xy_heatmap_off1_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_secondary_radius_vs_angle_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_primary_radius_vs_angle_multi_derive_incident_angle_SSTS-01.png
- output_file: logs/incident_angles_derive_incident_angle_SSTS-01_off1.log
test_name: incident_angles_dual_mirror_debug_plots
schema_name: application_workflow.metaschema
schema_version: 0.4.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
applications:
- application: simtools-derive-incident-angle
configuration:
site: South
telescope: SSTS-01
off_axis_angles: [1.0, 2.0]
number_of_photons: 10000
model_version: 6.0.2
output_path: simtools-output
debug_plots: true
calculate_primary_secondary_angles: true
integration_tests:
- output_file: incident_angles/incident_angles_derive_incident_angle_SSTS-01_off1.ecsv
- output_file: incident_angles/incident_angles_derive_incident_angle_SSTS-01_off2.ecsv
- output_file: plots/incident_angles_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_angles_primary_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_secondary_xy_heatmap_off1_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_primary_xy_heatmap_off1_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_secondary_radius_vs_angle_multi_derive_incident_angle_SSTS-01.png
- output_file: plots/incident_primary_radius_vs_angle_multi_derive_incident_angle_SSTS-01.png
- output_file: logs/incident_angles_derive_incident_angle_SSTS-01_off1.log
- output_file: logs/incident_angles_derive_incident_angle_SSTS-01_off2.log
test_name: incident_angles_dual_mirror_debug_plots
schema_name: application_workflow.metaschema
schema_version: 0.4.0
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
applications:
- application: simtools-calculate-incident-angles
- application: simtools-derive-incident-angle
configuration:
site: South
telescope: LSTS-04
Expand All @@ -9,9 +9,9 @@ applications:
model_version: 6.0.2
output_path: simtools-output
integration_tests:
- output_file: incident_angles/incident_angles_calculate_incident_angles_LSTS-04_off1.ecsv
- output_file: plots/incident_angles_multi_calculate_incident_angles_LSTS-04.png
- output_file: logs/incident_angles_calculate_incident_angles_LSTS-04_off1.log
- output_file: incident_angles/incident_angles_derive_incident_angle_LSTS-04_off1.ecsv
- output_file: plots/incident_angles_multi_derive_incident_angle_LSTS-04.png
- output_file: logs/incident_angles_derive_incident_angle_LSTS-04_off1.log
test_name: incident_angles_single_mirror
schema_name: application_workflow.metaschema
schema_version: 0.4.0
Loading