diff --git a/include/AT_StoppingPower.h b/include/AT_StoppingPower.h index d1fe5bf7..7cd34bdf 100644 --- a/include/AT_StoppingPower.h +++ b/include/AT_StoppingPower.h @@ -273,4 +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); + #endif /* AT_STOPPINGPOWER_H_ */ diff --git a/include/AT_StoppingPowerDataICRU.h b/include/AT_StoppingPowerDataICRU.h index 5813e9e4..7101bb07 100644 --- a/include/AT_StoppingPowerDataICRU.h +++ b/include/AT_StoppingPowerDataICRU.h @@ -50,6 +50,25 @@ int AT_ICRU_wrapper( const long n, const char info[], double mass_stopping_power_MeV_cm2_g[]); +/** + * @brief Returns the minimum 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 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_MeV_u(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_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 5b4b9a92..4cd5d940 100644 --- a/include/AT_StoppingPowerDataPSTAR.h +++ b/include/AT_StoppingPowerDataPSTAR.h @@ -66,6 +66,25 @@ 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/u, or -1.0 if + * material_no is outside the PSTAR material range. + */ +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/u, or -1.0 if + * material_no is outside the PSTAR material range. + */ +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 * for Electrons, Protons, and Helium Ions diff --git a/src/AT_StoppingPower.c b/src/AT_StoppingPower.c index 7f8c8a0a..01431c5b 100644 --- a/src/AT_StoppingPower.c +++ b/src/AT_StoppingPower.c @@ -318,3 +318,35 @@ 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) +{ + 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, 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: + 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 350403a3..a7f729a2 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, @@ -128,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[], @@ -148,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; } @@ -178,3 +197,50 @@ int AT_ICRU_wrapper( const long n, return AT_Success; } +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 AT_No_ICRU_Data; + } + + long atomic_number = AT_Z_from_particle_no_single(particle_no); + if (!AT_ICRU_has_data_for_atomic_number(material_no, atomic_number)) { + 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 AT_Success; +} + +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, + &minimum, &maximum) != AT_Success) { + return -1.0; + } + return minimum; +} + +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, + &minimum, &maximum) != AT_Success) { + return -1.0; + } + return maximum; +} diff --git a/src/AT_StoppingPowerDataPSTAR.c b/src/AT_StoppingPowerDataPSTAR.c index 5991f801..f26c5959 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 @@ -1341,3 +1342,37 @@ int AT_PSTAR_wrapper( const long n, return AT_Success; } +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_MeV_u(long material_no) { + double minimum; + double maximum; + if (AT_PSTAR_energy_bounds(material_no, &minimum, &maximum) != AT_Success) { + return -1.0; + } + return AT_E_MeV_u_from_E_MeV(minimum, PARTICLE_PROTON_NUMBER); +} + +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 AT_E_MeV_u_from_E_MeV(maximum, PARTICLE_PROTON_NUMBER); +} \ No newline at end of file