From ed81e84b030f43621c9e4b5c77445d55d618285c Mon Sep 17 00:00:00 2001 From: witNie Date: Fri, 16 Oct 2026 22:08:45 +0200 Subject: [PATCH 1/8] Add energy bounds functions for ICRU and PSTAR data --- include/AT_StoppingPowerDataICRU.h | 5 +++++ include/AT_StoppingPowerDataPSTAR.h | 5 +++++ src/AT_StoppingPowerDataICRU.c | 23 +++++++++++++++++++++++ src/AT_StoppingPowerDataPSTAR.c | 17 +++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/include/AT_StoppingPowerDataICRU.h b/include/AT_StoppingPowerDataICRU.h index 5813e9e4..c21161fe 100644 --- a/include/AT_StoppingPowerDataICRU.h +++ b/include/AT_StoppingPowerDataICRU.h @@ -51,6 +51,11 @@ int AT_ICRU_wrapper( const long n, double mass_stopping_power_MeV_cm2_g[]); +int AT_ICRU_energy_bounds( long material_no, + long particle_no, + double *minimum, + double *maximum); + /** * @struct AT_stopping_power_ICRU_table * TODO diff --git a/include/AT_StoppingPowerDataPSTAR.h b/include/AT_StoppingPowerDataPSTAR.h index 5b4b9a92..ed43abb4 100644 --- a/include/AT_StoppingPowerDataPSTAR.h +++ b/include/AT_StoppingPowerDataPSTAR.h @@ -66,6 +66,11 @@ int AT_PSTAR_wrapper( const long n, const char info[], double mass_stopping_power_MeV_cm2_g[]); + +int AT_PSTAR_energy_bounds( long material_no, + double *minimum, + double *maximum); + /** PSTAR data downloaded from NIST database: http://www.nist.gov/pml/data/star/index.cfm * Stopping-Power and Range Tables * for Electrons, Protons, and Helium Ions diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index 350403a3..65cd5eba 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -178,3 +178,26 @@ int AT_ICRU_wrapper( const long n, return AT_Success; } +int AT_ICRU_energy_bounds( + long material_no, + long particle_no, + double *minimum, + double *maximum) { + if (material_no != Water_Liquid && + material_no != Aluminum_Oxide) { + return -1; + } + long atomic_number = AT_Z_from_particle_no_single(particle_no); + if (atomic_number > 18) { + return -1; + } + const AT_stopping_power_ICRU_table_struct *table = + &AT_stopping_power_ICRU_table[material_no - 1]; + *minimum = table->energy_and_stopping_power[0][0]; + *maximum = table->energy_and_stopping_power[0] + [table->number_of_data_points - 1]; + if (atomic_number == 2) { + *maximum = 250.0; + } + return 0; +} diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index 5991f801..e1d6d49c 100644 --- a/src/AT_StoppingPowerDataPSTAR.c +++ b/src/AT_StoppingPowerDataPSTAR.c @@ -1341,3 +1341,20 @@ int AT_PSTAR_wrapper( const long n, return AT_Success; } +int AT_PSTAR_energy_bounds( + long material_no, + double *minimum, + double *maximum) { + if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { + return -1; + } + const PSTAR_data_for_material_struct *table = + PSTAR_data.stopping_power_source_data[material_no]; + if (table == NULL || table->number_of_data_points <= 0) { + return -1; + } + *minimum = table->energy_and_stopping_power[0][0]; + *maximum = table->energy_and_stopping_power[ + table->number_of_data_points - 1][0]; + return 0; +} \ No newline at end of file From 46131eb6a3bd4cffcf8711515574878a2eb66e13 Mon Sep 17 00:00:00 2001 From: witNie Date: Sun, 18 Oct 2026 16:48:52 +0200 Subject: [PATCH 2/8] Enhance energy bounds functions for ICRU and PSTAR data with detailed documentation and error handling --- include/AT_StoppingPowerDataICRU.h | 11 ++++++++++- include/AT_StoppingPowerDataPSTAR.h | 12 ++++++++++-- src/AT_StoppingPowerDataICRU.c | 12 +++++++++--- src/AT_StoppingPowerDataPSTAR.c | 16 ++++++++++------ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/include/AT_StoppingPowerDataICRU.h b/include/AT_StoppingPowerDataICRU.h index c21161fe..dde0c0eb 100644 --- a/include/AT_StoppingPowerDataICRU.h +++ b/include/AT_StoppingPowerDataICRU.h @@ -50,7 +50,16 @@ int AT_ICRU_wrapper( const long n, const char info[], double mass_stopping_power_MeV_cm2_g[]); - +/** + * Returns the minimum and maximum kinetic energy per nucleon covered by the + * ICRU stopping-power table for a material and particle. + * + * @param[in] material_no Material number. + * @param[in] particle_no Particle number. + * @param[out] minimum Minimum kinetic energy in MeV/u. + * @param[out] maximum Maximum kinetic energy in MeV/u. + * @return AT_Success when data are available, or AT_No_ICRU_Data otherwise. + */ int AT_ICRU_energy_bounds( long material_no, long particle_no, double *minimum, diff --git a/include/AT_StoppingPowerDataPSTAR.h b/include/AT_StoppingPowerDataPSTAR.h index ed43abb4..49b0dd64 100644 --- a/include/AT_StoppingPowerDataPSTAR.h +++ b/include/AT_StoppingPowerDataPSTAR.h @@ -66,10 +66,18 @@ int AT_PSTAR_wrapper( const long n, const char info[], double mass_stopping_power_MeV_cm2_g[]); - +/** + * Returns the minimum and maximum kinetic energies covered by the PSTAR + * stopping-power table for a material. + * + * @param[in] material_no Material number. + * @param[out] minimum Minimum kinetic energy in MeV. + * @param[out] maximum Maximum kinetic energy in MeV. + * @return AT_Success when data are available, or AT_No_PSTAR_Data otherwise. + */ int AT_PSTAR_energy_bounds( long material_no, double *minimum, - double *maximum); + double *maximum); /** PSTAR data downloaded from NIST database: http://www.nist.gov/pml/data/star/index.cfm * Stopping-Power and Range Tables diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index 65cd5eba..f704f010 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -29,6 +29,7 @@ */ #include "AT_StoppingPowerDataICRU.h" +#include "AT_Error.h" AT_stopping_power_ICRU_table_struct AT_stopping_power_ICRU_table[2] = { { Water_Liquid, @@ -185,19 +186,24 @@ int AT_ICRU_energy_bounds( double *maximum) { if (material_no != Water_Liquid && material_no != Aluminum_Oxide) { - return -1; + return AT_No_ICRU_Data; } + long atomic_number = AT_Z_from_particle_no_single(particle_no); if (atomic_number > 18) { - return -1; + return AT_No_ICRU_Data; } + const AT_stopping_power_ICRU_table_struct *table = &AT_stopping_power_ICRU_table[material_no - 1]; + *minimum = table->energy_and_stopping_power[0][0]; *maximum = table->energy_and_stopping_power[0] [table->number_of_data_points - 1]; + if (atomic_number == 2) { *maximum = 250.0; } - return 0; + + return AT_Success; } diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index e1d6d49c..3856ada6 100644 --- a/src/AT_StoppingPowerDataPSTAR.c +++ b/src/AT_StoppingPowerDataPSTAR.c @@ -1,4 +1,5 @@ #include "AT_StoppingPowerDataPSTAR.h" +#include "AT_Error.h" /* * PSTAR contains experimental stopping power data for protons @@ -1346,15 +1347,18 @@ int AT_PSTAR_energy_bounds( double *minimum, double *maximum) { if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { - return -1; + return AT_No_PSTAR_Data; } + const PSTAR_data_for_material_struct *table = PSTAR_data.stopping_power_source_data[material_no]; - if (table == NULL || table->number_of_data_points <= 0) { - return -1; + if (table == NULL) { + return AT_No_PSTAR_Data; } + *minimum = table->energy_and_stopping_power[0][0]; *maximum = table->energy_and_stopping_power[ - table->number_of_data_points - 1][0]; - return 0; -} \ No newline at end of file + N_PSTAR_DATAPOINTS - 1][0]; + + return AT_Success; +} From b1df4d1004c22738da6b394c86b70a5ad5e4e66f Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 19:28:36 +0200 Subject: [PATCH 3/8] Refactor PSTAR energy bounds functions to return minimum and maximum energies directly, with error handling for invalid material numbers --- include/AT_StoppingPowerDataPSTAR.h | 24 +++++++++++++-------- src/AT_StoppingPowerDataPSTAR.c | 33 ++++++++++++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/include/AT_StoppingPowerDataPSTAR.h b/include/AT_StoppingPowerDataPSTAR.h index 49b0dd64..2e80cc1d 100644 --- a/include/AT_StoppingPowerDataPSTAR.h +++ b/include/AT_StoppingPowerDataPSTAR.h @@ -66,18 +66,24 @@ int AT_PSTAR_wrapper( const long n, const char info[], double mass_stopping_power_MeV_cm2_g[]); + +/** + * @brief Returns the minimum kinetic energy covered by the PSTAR data. + * + * @param[in] material_no Material number identifying the material. + * @return Minimum tabulated kinetic energy in MeV, or -1.0 if + * material_no is outside the PSTAR material range. + */ +double AT_PSTAR_min_energy(long material_no); + /** - * Returns the minimum and maximum kinetic energies covered by the PSTAR - * stopping-power table for a material. + * @brief Returns the maximum kinetic energy covered by the PSTAR data. * - * @param[in] material_no Material number. - * @param[out] minimum Minimum kinetic energy in MeV. - * @param[out] maximum Maximum kinetic energy in MeV. - * @return AT_Success when data are available, or AT_No_PSTAR_Data otherwise. + * @param[in] material_no Material number identifying the material. + * @return Maximum tabulated kinetic energy in MeV, or -1.0 if + * material_no is outside the PSTAR material range. */ -int AT_PSTAR_energy_bounds( long material_no, - double *minimum, - double *maximum); +double AT_PSTAR_max_energy(long material_no); /** PSTAR data downloaded from NIST database: http://www.nist.gov/pml/data/star/index.cfm * Stopping-Power and Range Tables diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index 3856ada6..43359139 100644 --- a/src/AT_StoppingPowerDataPSTAR.c +++ b/src/AT_StoppingPowerDataPSTAR.c @@ -1342,23 +1342,18 @@ int AT_PSTAR_wrapper( const long n, return AT_Success; } -int AT_PSTAR_energy_bounds( - long material_no, - double *minimum, - double *maximum) { - if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { - return AT_No_PSTAR_Data; - } - - const PSTAR_data_for_material_struct *table = - PSTAR_data.stopping_power_source_data[material_no]; - if (table == NULL) { - return AT_No_PSTAR_Data; - } - - *minimum = table->energy_and_stopping_power[0][0]; - *maximum = table->energy_and_stopping_power[ - N_PSTAR_DATAPOINTS - 1][0]; - - return AT_Success; +double AT_PSTAR_min_energy(long material_no) { + double min_energy; + if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { + return -1.0; + } + return PSTAR_data.stopping_power_source_data[material_no]->energy_and_stopping_power[0][0]; } + +double AT_PSTAR_max_energy(long material_no) { + double max_energy; + if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { + return -1.0; + } + return PSTAR_data.stopping_power_source_data[material_no]->energy_and_stopping_power[N_PSTAR_DATAPOINTS - 1][0]; +} \ No newline at end of file From 023576f5f3c2d859ec2799d49ee607e9d309e5aa Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 19:31:37 +0200 Subject: [PATCH 4/8] Refactor ICRU energy bounds functions to return minimum and maximum energies directly, with error handling for invalid material numbers --- include/AT_StoppingPowerDataICRU.h | 27 +++++++++++++---------- src/AT_StoppingPowerDataICRU.c | 35 ++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/AT_StoppingPowerDataICRU.h b/include/AT_StoppingPowerDataICRU.h index dde0c0eb..269118ed 100644 --- a/include/AT_StoppingPowerDataICRU.h +++ b/include/AT_StoppingPowerDataICRU.h @@ -51,19 +51,24 @@ int AT_ICRU_wrapper( const long n, double mass_stopping_power_MeV_cm2_g[]); /** - * Returns the minimum and maximum kinetic energy per nucleon covered by the - * ICRU stopping-power table for a material and particle. + * @brief Returns the minimum kinetic energy covered by the ICRU data. * - * @param[in] material_no Material number. - * @param[in] particle_no Particle number. - * @param[out] minimum Minimum kinetic energy in MeV/u. - * @param[out] maximum Maximum kinetic energy in MeV/u. - * @return AT_Success when data are available, or AT_No_ICRU_Data otherwise. + * @param[in] material_no Material number identifying the material. + * @param[in] particle_no Particle number identifying the particle. + * @return Minimum tabulated kinetic energy in MeV/u, or -1.0 if + * material_no or particle_no has no ICRU data. */ -int AT_ICRU_energy_bounds( long material_no, - long particle_no, - double *minimum, - double *maximum); +double AT_ICRU_min_energy(long material_no, long particle_no); + +/** + * @brief Returns the maximum kinetic energy covered by the ICRU data. + * + * @param[in] material_no Material number identifying the material. + * @param[in] particle_no Particle number identifying the particle. + * @return Maximum tabulated kinetic energy in MeV/u, or -1.0 if + * material_no or particle_no has no ICRU data. + */ +double AT_ICRU_max_energy(long material_no, long particle_no); /** * @struct AT_stopping_power_ICRU_table diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index f704f010..4a771128 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -179,31 +179,42 @@ int AT_ICRU_wrapper( const long n, return AT_Success; } -int AT_ICRU_energy_bounds( - long material_no, - long particle_no, - double *minimum, - double *maximum) { +double AT_ICRU_min_energy(long material_no, long particle_no) { if (material_no != Water_Liquid && material_no != Aluminum_Oxide) { - return AT_No_ICRU_Data; + return -1.0; } long atomic_number = AT_Z_from_particle_no_single(particle_no); if (atomic_number > 18) { - return AT_No_ICRU_Data; + return -1.0; } const AT_stopping_power_ICRU_table_struct *table = &AT_stopping_power_ICRU_table[material_no - 1]; - *minimum = table->energy_and_stopping_power[0][0]; - *maximum = table->energy_and_stopping_power[0] - [table->number_of_data_points - 1]; + return table->energy_and_stopping_power[0][0]; +} + +double AT_ICRU_max_energy(long material_no, long particle_no) { + if (material_no != Water_Liquid && + material_no != Aluminum_Oxide) { + return -1.0; + } + + long atomic_number = AT_Z_from_particle_no_single(particle_no); + if (atomic_number > 18) { + return -1.0; + } + const AT_stopping_power_ICRU_table_struct *table = + &AT_stopping_power_ICRU_table[material_no - 1]; + + double maximum = table->energy_and_stopping_power[0] + [table->number_of_data_points - 1]; if (atomic_number == 2) { - *maximum = 250.0; + maximum = 250.0; } - return AT_Success; + return maximum; } From 69cbac40958004591c8ddc81657e9f055fbaedbd Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 19:34:10 +0200 Subject: [PATCH 5/8] added back old functions for PSTAR and ICRU data --- src/AT_StoppingPowerDataICRU.c | 46 +++++++++++++++++++-------------- src/AT_StoppingPowerDataPSTAR.c | 31 +++++++++++++++++----- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index 4a771128..bd8c14da 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -179,42 +179,50 @@ int AT_ICRU_wrapper( const long n, return AT_Success; } -double AT_ICRU_min_energy(long material_no, long particle_no) { +static int AT_ICRU_energy_bounds(long material_no, + long particle_no, + double *minimum, + double *maximum) { if (material_no != Water_Liquid && material_no != Aluminum_Oxide) { - return -1.0; + return AT_No_ICRU_Data; } long atomic_number = AT_Z_from_particle_no_single(particle_no); if (atomic_number > 18) { - return -1.0; + return AT_No_ICRU_Data; } const AT_stopping_power_ICRU_table_struct *table = &AT_stopping_power_ICRU_table[material_no - 1]; - return table->energy_and_stopping_power[0][0]; -} + *minimum = table->energy_and_stopping_power[0][0]; + *maximum = table->energy_and_stopping_power[0] + [table->number_of_data_points - 1]; -double AT_ICRU_max_energy(long material_no, long particle_no) { - if (material_no != Water_Liquid && - material_no != Aluminum_Oxide) { - return -1.0; + if (atomic_number == 2) { + *maximum = 250.0; } - long atomic_number = AT_Z_from_particle_no_single(particle_no); - if (atomic_number > 18) { + return AT_Success; +} + +double AT_ICRU_min_energy(long material_no, long particle_no) { + double minimum; + double maximum; + if (AT_ICRU_energy_bounds(material_no, particle_no, + &minimum, &maximum) != AT_Success) { return -1.0; } + return minimum; +} - const AT_stopping_power_ICRU_table_struct *table = - &AT_stopping_power_ICRU_table[material_no - 1]; - - double maximum = table->energy_and_stopping_power[0] - [table->number_of_data_points - 1]; - if (atomic_number == 2) { - maximum = 250.0; +double AT_ICRU_max_energy(long material_no, long particle_no) { + double minimum; + double maximum; + if (AT_ICRU_energy_bounds(material_no, particle_no, + &minimum, &maximum) != AT_Success) { + return -1.0; } - return maximum; } diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index 43359139..37989f1a 100644 --- a/src/AT_StoppingPowerDataPSTAR.c +++ b/src/AT_StoppingPowerDataPSTAR.c @@ -1342,18 +1342,37 @@ int AT_PSTAR_wrapper( const long n, return AT_Success; } -double AT_PSTAR_min_energy(long material_no) { - double min_energy; +static int AT_PSTAR_energy_bounds(long material_no, + double *minimum, + double *maximum) { if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { + return AT_No_PSTAR_Data; + } + + *minimum = + PSTAR_data.stopping_power_source_data[material_no] + ->energy_and_stopping_power[0][0]; + *maximum = + PSTAR_data.stopping_power_source_data[material_no] + ->energy_and_stopping_power[N_PSTAR_DATAPOINTS - 1][0]; + + return AT_Success; +} + +double AT_PSTAR_min_energy(long material_no) { + double minimum; + double maximum; + if (AT_PSTAR_energy_bounds(material_no, &minimum, &maximum) != AT_Success) { return -1.0; } - return PSTAR_data.stopping_power_source_data[material_no]->energy_and_stopping_power[0][0]; + return minimum; } double AT_PSTAR_max_energy(long material_no) { - double max_energy; - if (material_no < 0 || material_no >= N_PSTAR_MATERIALS) { + double minimum; + double maximum; + if (AT_PSTAR_energy_bounds(material_no, &minimum, &maximum) != AT_Success) { return -1.0; } - return PSTAR_data.stopping_power_source_data[material_no]->energy_and_stopping_power[N_PSTAR_DATAPOINTS - 1][0]; + return maximum; } \ No newline at end of file From 75fe32f90e80b48624325d00ccdf4f0feb6cdf5d Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 20:00:52 +0200 Subject: [PATCH 6/8] added helper for checking awailable stopping power data --- include/AT_StoppingPower.h | 4 ++++ src/AT_StoppingPower.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/AT_StoppingPower.h b/include/AT_StoppingPower.h index d1fe5bf7..f57a7cec 100644 --- a/include/AT_StoppingPower.h +++ b/include/AT_StoppingPower.h @@ -273,4 +273,8 @@ double AT_Mass_Stopping_Power_E_MeV_u_single( const long stopping_power_source_n const double E_MeV_u, const long particle_no, const long material_no); + +int AT_Stopping_Power_has_data(const long stopping_power_source_no, + const long particle_no, const long material_no); + #endif /* AT_STOPPINGPOWER_H_ */ diff --git a/src/AT_StoppingPower.c b/src/AT_StoppingPower.c index 7f8c8a0a..d4db20e9 100644 --- a/src/AT_StoppingPower.c +++ b/src/AT_StoppingPower.c @@ -318,3 +318,37 @@ double AT_Mass_Stopping_Power_E_MeV_u_single( const long stopping_power_source_n &stopping_power_MeV_cm2_g); return stopping_power_MeV_cm2_g; } + +int AT_Stopping_Power_has_data(const long stopping_power_source_no, + const long particle_no, + const long material_no) +{ + const long Z = AT_Z_from_particle_no_single(particle_no); + const long A = AT_A_from_particle_no_single(particle_no); + if (Z < 0 || A < 0) { + return 0; + } + switch (stopping_power_source_no) { + case FromFile: + /* + * The filename and file contents are not provided here, + * so availability cannot be checked. + */ + return 0; + case Bethe: + /* + * Bethe is an analytical model and supports all + * defined materials and particles. + */ + return material_no >= 0 && material_no < MATERIAL_DATA_N; + case PSTAR: + return material_no >= Water_Liquid && + material_no <= Copper; + case ICRU: + return (material_no == Water_Liquid || + material_no == Aluminum_Oxide) && + Z <= 18; + default: + return 0; + } +} From 938591da7d9b937e9b683dc193c4e5d6b732a058 Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 20:03:23 +0200 Subject: [PATCH 7/8] renamed functions to include units --- include/AT_StoppingPowerDataICRU.h | 4 ++-- include/AT_StoppingPowerDataPSTAR.h | 8 ++++---- src/AT_StoppingPowerDataICRU.c | 4 ++-- src/AT_StoppingPowerDataPSTAR.c | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/AT_StoppingPowerDataICRU.h b/include/AT_StoppingPowerDataICRU.h index 269118ed..7101bb07 100644 --- a/include/AT_StoppingPowerDataICRU.h +++ b/include/AT_StoppingPowerDataICRU.h @@ -58,7 +58,7 @@ int AT_ICRU_wrapper( const long n, * @return Minimum tabulated kinetic energy in MeV/u, or -1.0 if * material_no or particle_no has no ICRU data. */ -double AT_ICRU_min_energy(long material_no, long particle_no); +double AT_ICRU_min_energy_MeV_u(long material_no, long particle_no); /** * @brief Returns the maximum kinetic energy covered by the ICRU data. @@ -68,7 +68,7 @@ double AT_ICRU_min_energy(long material_no, long particle_no); * @return Maximum tabulated kinetic energy in MeV/u, or -1.0 if * material_no or particle_no has no ICRU data. */ -double AT_ICRU_max_energy(long material_no, long particle_no); +double AT_ICRU_max_energy_MeV_u(long material_no, long particle_no); /** * @struct AT_stopping_power_ICRU_table diff --git a/include/AT_StoppingPowerDataPSTAR.h b/include/AT_StoppingPowerDataPSTAR.h index 2e80cc1d..4cd5d940 100644 --- a/include/AT_StoppingPowerDataPSTAR.h +++ b/include/AT_StoppingPowerDataPSTAR.h @@ -71,19 +71,19 @@ int AT_PSTAR_wrapper( const long n, * @brief Returns the minimum kinetic energy covered by the PSTAR data. * * @param[in] material_no Material number identifying the material. - * @return Minimum tabulated kinetic energy in MeV, or -1.0 if + * @return Minimum tabulated kinetic energy in MeV/u, or -1.0 if * material_no is outside the PSTAR material range. */ -double AT_PSTAR_min_energy(long material_no); +double AT_PSTAR_min_energy_MeV_u(long material_no); /** * @brief Returns the maximum kinetic energy covered by the PSTAR data. * * @param[in] material_no Material number identifying the material. - * @return Maximum tabulated kinetic energy in MeV, or -1.0 if + * @return Maximum tabulated kinetic energy in MeV/u, or -1.0 if * material_no is outside the PSTAR material range. */ -double AT_PSTAR_max_energy(long material_no); +double AT_PSTAR_max_energy_MeV_u(long material_no); /** PSTAR data downloaded from NIST database: http://www.nist.gov/pml/data/star/index.cfm * Stopping-Power and Range Tables diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index bd8c14da..9fc14a72 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -207,7 +207,7 @@ static int AT_ICRU_energy_bounds(long material_no, return AT_Success; } -double AT_ICRU_min_energy(long material_no, long particle_no) { +double AT_ICRU_min_energy_MeV_u(long material_no, long particle_no) { double minimum; double maximum; if (AT_ICRU_energy_bounds(material_no, particle_no, @@ -217,7 +217,7 @@ double AT_ICRU_min_energy(long material_no, long particle_no) { return minimum; } -double AT_ICRU_max_energy(long material_no, long particle_no) { +double AT_ICRU_max_energy_MeV_u(long material_no, long particle_no) { double minimum; double maximum; if (AT_ICRU_energy_bounds(material_no, particle_no, diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index 37989f1a..f26c5959 100644 --- a/src/AT_StoppingPowerDataPSTAR.c +++ b/src/AT_StoppingPowerDataPSTAR.c @@ -1359,20 +1359,20 @@ static int AT_PSTAR_energy_bounds(long material_no, return AT_Success; } -double AT_PSTAR_min_energy(long material_no) { +double AT_PSTAR_min_energy_MeV_u(long material_no) { double minimum; double maximum; if (AT_PSTAR_energy_bounds(material_no, &minimum, &maximum) != AT_Success) { return -1.0; } - return minimum; + return AT_E_MeV_u_from_E_MeV(minimum, PARTICLE_PROTON_NUMBER); } -double AT_PSTAR_max_energy(long material_no) { +double AT_PSTAR_max_energy_MeV_u(long material_no) { double minimum; double maximum; if (AT_PSTAR_energy_bounds(material_no, &minimum, &maximum) != AT_Success) { return -1.0; } - return maximum; + return AT_E_MeV_u_from_E_MeV(maximum, PARTICLE_PROTON_NUMBER); } \ No newline at end of file From 011eead41cc76bdc3ff3f871a78e25a440685f2c Mon Sep 17 00:00:00 2001 From: witNie Date: Mon, 19 Oct 2026 20:12:43 +0200 Subject: [PATCH 8/8] added utils for ICRU validation --- include/AT_StoppingPower.h | 13 +++++++++++-- src/AT_StoppingPower.c | 24 +++++++++++------------- src/AT_StoppingPowerDataICRU.c | 22 ++++++++++++++++++++-- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/include/AT_StoppingPower.h b/include/AT_StoppingPower.h index f57a7cec..7cd34bdf 100644 --- a/include/AT_StoppingPower.h +++ b/include/AT_StoppingPower.h @@ -273,8 +273,17 @@ double AT_Mass_Stopping_Power_E_MeV_u_single( const long stopping_power_source_n const double E_MeV_u, const long particle_no, const long material_no); - +/** + * Checks whether stopping-power data are available for a source, + * particle, and material combination. + * + * @param[in] stopping_power_source_no stopping-power data-source id + * @param[in] particle_no particle number + * @param[in] material_no material number + * @return 1 if data are available, or 0 otherwise + */ int AT_Stopping_Power_has_data(const long stopping_power_source_no, - const long particle_no, const long material_no); + const long particle_no, + const long material_no); #endif /* AT_STOPPINGPOWER_H_ */ diff --git a/src/AT_StoppingPower.c b/src/AT_StoppingPower.c index d4db20e9..01431c5b 100644 --- a/src/AT_StoppingPower.c +++ b/src/AT_StoppingPower.c @@ -323,11 +323,6 @@ int AT_Stopping_Power_has_data(const long stopping_power_source_no, const long particle_no, const long material_no) { - const long Z = AT_Z_from_particle_no_single(particle_no); - const long A = AT_A_from_particle_no_single(particle_no); - if (Z < 0 || A < 0) { - return 0; - } switch (stopping_power_source_no) { case FromFile: /* @@ -336,18 +331,21 @@ int AT_Stopping_Power_has_data(const long stopping_power_source_no, */ return 0; case Bethe: - /* - * Bethe is an analytical model and supports all - * defined materials and particles. - */ - return material_no >= 0 && material_no < MATERIAL_DATA_N; + /* Bethe is an analytical model, not a finite data table. */ + return 1; case PSTAR: + if (AT_Z_from_particle_no_single(particle_no) < 1 || + AT_A_from_particle_no_single(particle_no) < 1) { + return 0; + } return material_no >= Water_Liquid && material_no <= Copper; case ICRU: - return (material_no == Water_Liquid || - material_no == Aluminum_Oxide) && - Z <= 18; + if (AT_Z_from_particle_no_single(particle_no) < 1 || + AT_A_from_particle_no_single(particle_no) < 1) { + return 0; + } + return AT_ICRU_min_energy_MeV_u(material_no, particle_no) >= 0.0; default: return 0; } diff --git a/src/AT_StoppingPowerDataICRU.c b/src/AT_StoppingPowerDataICRU.c index 9fc14a72..a7f729a2 100644 --- a/src/AT_StoppingPowerDataICRU.c +++ b/src/AT_StoppingPowerDataICRU.c @@ -129,6 +129,24 @@ AT_stopping_power_ICRU_table_struct AT_stopping_power_ICRU_table[2] = { +static long AT_ICRU_max_atomic_number(const long material_no) { + if (material_no == Water_Liquid) { + return 18; + } + if (material_no == Aluminum_Oxide) { + return 10; + } + return 0; +} + +static int AT_ICRU_has_data_for_atomic_number( + const long material_no, + const long atomic_number) { + const long max_atomic_number = + AT_ICRU_max_atomic_number(material_no); + return atomic_number >= 1 && atomic_number <= max_atomic_number; +} + int AT_ICRU_wrapper( const long n, const double E_MeV_u[], const long particle_no[], @@ -149,7 +167,7 @@ int AT_ICRU_wrapper( const long n, for(i = 0; i < n; i++){ - if( Z[i] > 18){ /* Data for H ... Ar */ + if(!AT_ICRU_has_data_for_atomic_number(material_no, Z[i])){ mass_stopping_power_MeV_cm2_g[i] = -1.0; continue; } @@ -189,7 +207,7 @@ static int AT_ICRU_energy_bounds(long material_no, } long atomic_number = AT_Z_from_particle_no_single(particle_no); - if (atomic_number > 18) { + if (!AT_ICRU_has_data_for_atomic_number(material_no, atomic_number)) { return AT_No_ICRU_Data; }