diff --git a/doc/RTD/source/Planetary/equations_of_state.rst b/doc/RTD/source/Planetary/equations_of_state.rst index d20cbd83ff0efdbc1f73c3a59a310d71155abda1..37b175c53737288374fe1a4afec07a280c3bbd53 100644 --- a/doc/RTD/source/Planetary/equations_of_state.rst +++ b/doc/RTD/source/Planetary/equations_of_state.rst @@ -36,6 +36,8 @@ planetary initial conditions, `WoMa <https://github.com/srbonilla/WoMa>`_: + Granite: ``101`` + Water: ``102`` + Basalt: ``103`` + + Ice: ``104`` + + Custom user-provided parameters: ``190``, ``191``, ..., ``199`` + Hubbard \& MacFarlane (1980): ``2`` + Hydrogen-helium atmosphere: ``200`` + Ice H20-CH4-NH3 mix: ``201`` @@ -45,6 +47,10 @@ planetary initial conditions, `WoMa <https://github.com/srbonilla/WoMa>`_: + Basalt (7530): ``301`` + Water (7154): ``302`` + Senft \& Stewart (2008) water: ``303`` + + AQUA, Haldemann, J. et al. (2020) water: ``304`` + + Chabrier, G. et al. (2019) Hydrogen: ``305`` + + Chabrier, G. et al. (2019) Helium: ``306`` + + Chabrier & Debras (2021) H/He mixture Y=0.245 (Jupiter): ``307`` + ANEOS (in SESAME-style tables): ``4`` + Forsterite (Stewart et al. 2019): ``400`` + Iron (Stewart, zenodo.org/record/3866507): ``401`` @@ -56,7 +62,7 @@ The data files for the tabulated EoS can be downloaded using the ``examples/Planetary/EoSTables/get_eos_tables.sh`` script. To enable one or multiple EoS, the corresponding ``planetary_use_*:`` -flag(s) must be set to ``1`` in the parameter file for a simulation, +flag(s) must be set from ``0`` to ``1`` in the parameter file for a simulation, along with the path to any table files, which are set by the ``planetary_*_table_file:`` parameters, as detailed in :ref:`Parameters_eos` and ``examples/parameter_example.yml``. diff --git a/examples/Planetary/EoSTables/get_eos_tables.sh b/examples/Planetary/EoSTables/get_eos_tables.sh index aaae425fd5dd9e22490291f966d1f9c76e76f30e..e47f08816dac41099cde2b980772c7320c9567bb 100755 --- a/examples/Planetary/EoSTables/get_eos_tables.sh +++ b/examples/Planetary/EoSTables/get_eos_tables.sh @@ -7,6 +7,10 @@ wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/SESAME_basalt_7530.txt wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/SESAME_iron_2140.txt wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/SESAME_water_7154.txt wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/SS08_water.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/AQUA_H20.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/CMS19_H.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/CMS19_He.txt +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/CD21_HHe.txt wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/ANEOS_forsterite_S19.txt wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/EoS/ANEOS_iron_S20.txt diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index ca3258a13db07cd11957cddcdb85d8004e56f705..e980b021603b6632c42f95b30336c2b7b21cc75a 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -314,6 +314,17 @@ EoS: planetary_use_Til_granite: 1 # Tillotson granite, material ID 101 planetary_use_Til_water: 0 # Tillotson water, material ID 102 planetary_use_Til_basalt: 0 # Tillotson basalt, material ID 103 + planetary_use_Til_ice: 0 # Tillotson ice, material ID 104 + planetary_use_Til_custom_0: 0 # Tillotson generic user-provided parameters, material IDs 19[0-9] + planetary_use_Til_custom_1: 0 + planetary_use_Til_custom_2: 0 + planetary_use_Til_custom_3: 0 + planetary_use_Til_custom_4: 0 + planetary_use_Til_custom_5: 0 + planetary_use_Til_custom_6: 0 + planetary_use_Til_custom_7: 0 + planetary_use_Til_custom_8: 0 + planetary_use_Til_custom_9: 0 planetary_use_HM80_HHe: 0 # Hubbard & MacFarlane (1980) hydrogen-helium atmosphere, material ID 200 planetary_use_HM80_ice: 0 # Hubbard & MacFarlane (1980) H20-CH4-NH3 ice mix, material ID 201 planetary_use_HM80_rock: 0 # Hubbard & MacFarlane (1980) SiO2-MgO-FeS-FeO rock mix, material ID 202 @@ -321,6 +332,10 @@ EoS: planetary_use_SESAME_basalt: 0 # SESAME basalt 7530, material ID 301 planetary_use_SESAME_water: 0 # SESAME water 7154, material ID 302 planetary_use_SS08_water: 0 # Senft & Stewart (2008) SESAME-like water, material ID 303 + planetary_use_AQUA: 0 # Haldemann, J. et al. (2020) water, material ID 304 + planetary_use_CMS19_H: 0 # Chabrier, G. et al. (2019) Hydrogen, material ID 305 + planetary_use_CMS19_He: 0 # Chabrier, G. et al. (2019) Hydrogen, material ID 306 + planetary_use_CD21_HHe: 0 # Chabrier & Debras (2021) H/He mixture Y=0.245 (Jupiter), material ID 307 planetary_use_ANEOS_forsterite: 0 # ANEOS forsterite (Stewart et al. 2019), material ID 400 planetary_use_ANEOS_iron: 0 # ANEOS iron (Stewart 2020), material ID 401 planetary_use_ANEOS_Fe85Si15: 0 # ANEOS Fe85Si15 (Stewart 2020), material ID 402 @@ -335,6 +350,16 @@ EoS: planetary_use_custom_8: 0 planetary_use_custom_9: 0 # Tablulated EoS file paths. + planetary_Til_custom_0_param_file: ./EoSTables/Til_custom_0.txt + planetary_Til_custom_1_param_file: ./EoSTables/Til_custom_1.txt + planetary_Til_custom_2_param_file: ./EoSTables/Til_custom_2.txt + planetary_Til_custom_3_param_file: ./EoSTables/Til_custom_3.txt + planetary_Til_custom_4_param_file: ./EoSTables/Til_custom_4.txt + planetary_Til_custom_5_param_file: ./EoSTables/Til_custom_5.txt + planetary_Til_custom_6_param_file: ./EoSTables/Til_custom_6.txt + planetary_Til_custom_7_param_file: ./EoSTables/Til_custom_7.txt + planetary_Til_custom_8_param_file: ./EoSTables/Til_custom_8.txt + planetary_Til_custom_9_param_file: ./EoSTables/Til_custom_9.txt planetary_HM80_HHe_table_file: ./EoSTables/HM80_HHe.txt planetary_HM80_ice_table_file: ./EoSTables/HM80_ice.txt planetary_HM80_rock_table_file: ./EoSTables/HM80_rock.txt diff --git a/src/equation_of_state/barotropic/equation_of_state.h b/src/equation_of_state/barotropic/equation_of_state.h index d91b0c0ce4cfe8b864f773c877d755f8dfcf77a7..71be2944437879bb0fa65142d7674fa830ed824c 100644 --- a/src/equation_of_state/barotropic/equation_of_state.h +++ b/src/equation_of_state/barotropic/equation_of_state.h @@ -56,7 +56,7 @@ struct eos_parameters { * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_internal_energy_from_entropy(float density, float entropy) { +gas_internal_energy_from_entropy(const float density, const float entropy) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -76,7 +76,7 @@ gas_internal_energy_from_entropy(float density, float entropy) { * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_pressure_from_entropy(float density, float entropy) { +gas_pressure_from_entropy(const float density, const float entropy) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -96,7 +96,7 @@ gas_pressure_from_entropy(float density, float entropy) { * @return The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_entropy_from_pressure(float density, float pressure) { +gas_entropy_from_pressure(const float density, const float pressure) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -116,7 +116,7 @@ gas_entropy_from_pressure(float density, float pressure) { * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_entropy(float density, float entropy) { +gas_soundspeed_from_entropy(const float density, const float entropy) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -135,7 +135,7 @@ gas_soundspeed_from_entropy(float density, float entropy) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_entropy_from_internal_energy(float density, float u) { +gas_entropy_from_internal_energy(const float density, const float u) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -155,7 +155,7 @@ gas_entropy_from_internal_energy(float density, float u) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_pressure_from_internal_energy(float density, float u) { +gas_pressure_from_internal_energy(const float density, const float u) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -175,7 +175,7 @@ gas_pressure_from_internal_energy(float density, float u) { * @return The internal energy \f$u\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_internal_energy_from_pressure(float density, float pressure) { +gas_internal_energy_from_pressure(const float density, const float pressure) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -195,7 +195,7 @@ gas_internal_energy_from_pressure(float density, float pressure) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_internal_energy(float density, float u) { +gas_soundspeed_from_internal_energy(const float density, const float u) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -214,7 +214,7 @@ gas_soundspeed_from_internal_energy(float density, float u) { * @param P The pressure \f$P\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_pressure(float density, float P) { +gas_soundspeed_from_pressure(const float density, const float P) { const float density_frac = density * eos.inverse_core_density; const float density_factor = pow_gamma(density_frac); @@ -241,7 +241,7 @@ INLINE static void eos_init(struct eos_parameters *e, parser_get_param_float(params, "EoS:barotropic_vacuum_sound_speed"); e->vacuum_sound_speed2 = vacuum_sound_speed * vacuum_sound_speed; e->inverse_core_density = - 1. / parser_get_param_float(params, "EoS:barotropic_core_density"); + 1.f / parser_get_param_float(params, "EoS:barotropic_core_density"); } /** * @brief Print the equation of state diff --git a/src/equation_of_state/ideal_gas/equation_of_state.h b/src/equation_of_state/ideal_gas/equation_of_state.h index cfdff5c7fd4af8052cf4a36b8bace66718e235e5..61d76e4fb36d204f9c40ef3c76a7d875ff59a5be 100644 --- a/src/equation_of_state/ideal_gas/equation_of_state.h +++ b/src/equation_of_state/ideal_gas/equation_of_state.h @@ -46,7 +46,7 @@ struct eos_parameters {}; * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_internal_energy_from_entropy(float density, float entropy) { +gas_internal_energy_from_entropy(const float density, const float entropy) { return entropy * pow_gamma_minus_one(density) * hydro_one_over_gamma_minus_one; @@ -61,7 +61,7 @@ gas_internal_energy_from_entropy(float density, float entropy) { * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_pressure_from_entropy(float density, float entropy) { +gas_pressure_from_entropy(const float density, const float entropy) { return entropy * pow_gamma(density); } @@ -76,7 +76,7 @@ gas_pressure_from_entropy(float density, float entropy) { * @return The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_entropy_from_pressure(float density, float pressure) { +gas_entropy_from_pressure(const float density, const float pressure) { return pressure * pow_minus_gamma(density); } @@ -90,7 +90,7 @@ gas_entropy_from_pressure(float density, float pressure) { * @param entropy The entropy \f$A\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_entropy(float density, float entropy) { +gas_soundspeed_from_entropy(const float density, const float entropy) { return sqrtf(hydro_gamma * pow_gamma_minus_one(density) * entropy); } @@ -104,7 +104,7 @@ gas_soundspeed_from_entropy(float density, float entropy) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_entropy_from_internal_energy(float density, float u) { +gas_entropy_from_internal_energy(const float density, const float u) { return hydro_gamma_minus_one * u * pow_minus_gamma_minus_one(density); } @@ -118,7 +118,7 @@ gas_entropy_from_internal_energy(float density, float u) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_pressure_from_internal_energy(float density, float u) { +gas_pressure_from_internal_energy(const float density, const float u) { return hydro_gamma_minus_one * u * density; } @@ -133,7 +133,7 @@ gas_pressure_from_internal_energy(float density, float u) { * @return The internal energy \f$u\f$. */ __attribute__((always_inline, const)) INLINE static float -gas_internal_energy_from_pressure(float density, float pressure) { +gas_internal_energy_from_pressure(const float density, const float pressure) { return hydro_one_over_gamma_minus_one * pressure / density; } @@ -147,7 +147,7 @@ gas_internal_energy_from_pressure(float density, float pressure) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_internal_energy(float density, float u) { +gas_soundspeed_from_internal_energy(const float density, const float u) { return sqrtf(u * hydro_gamma * hydro_gamma_minus_one); } @@ -161,7 +161,7 @@ gas_soundspeed_from_internal_energy(float density, float u) { * @param P The pressure \f$P\f$ */ __attribute__((always_inline, const)) INLINE static float -gas_soundspeed_from_pressure(float density, float P) { +gas_soundspeed_from_pressure(const float density, const float P) { return sqrtf(hydro_gamma * P / density); } diff --git a/src/equation_of_state/isothermal/equation_of_state.h b/src/equation_of_state/isothermal/equation_of_state.h index 3ee1e18ebb0b8dcc6be8e02d4ee640edadfc35d6..0ff1b1a5063146e9630c588683d57c0993edff60 100644 --- a/src/equation_of_state/isothermal/equation_of_state.h +++ b/src/equation_of_state/isothermal/equation_of_state.h @@ -50,7 +50,7 @@ struct eos_parameters { * @param entropy The entropy \f$S\f$. */ __attribute__((always_inline)) INLINE static float -gas_internal_energy_from_entropy(float density, float entropy) { +gas_internal_energy_from_entropy(const float density, const float entropy) { return eos.isothermal_internal_energy; } @@ -65,7 +65,7 @@ gas_internal_energy_from_entropy(float density, float entropy) { * @param entropy The entropy \f$S\f$. */ __attribute__((always_inline)) INLINE static float gas_pressure_from_entropy( - float density, float entropy) { + const float density, const float entropy) { return hydro_gamma_minus_one * eos.isothermal_internal_energy * density; } @@ -81,7 +81,7 @@ __attribute__((always_inline)) INLINE static float gas_pressure_from_entropy( * @return The entropy \f$A\f$. */ __attribute__((always_inline)) INLINE static float gas_entropy_from_pressure( - float density, float pressure) { + const float density, const float pressure) { return hydro_gamma_minus_one * eos.isothermal_internal_energy * pow_minus_gamma_minus_one(density); @@ -98,7 +98,7 @@ __attribute__((always_inline)) INLINE static float gas_entropy_from_pressure( * @param entropy The entropy \f$S\f$. */ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy( - float density, float entropy) { + const float density, const float entropy) { return sqrtf(eos.isothermal_internal_energy * hydro_gamma * hydro_gamma_minus_one); @@ -114,7 +114,7 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy( * @param u The internal energy \f$u\f$ */ __attribute__((always_inline)) INLINE static float -gas_entropy_from_internal_energy(float density, float u) { +gas_entropy_from_internal_energy(const float density, const float u) { return hydro_gamma_minus_one * eos.isothermal_internal_energy * pow_minus_gamma_minus_one(density); @@ -130,7 +130,7 @@ gas_entropy_from_internal_energy(float density, float u) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline)) INLINE static float -gas_pressure_from_internal_energy(float density, float u) { +gas_pressure_from_internal_energy(const float density, const float u) { return hydro_gamma_minus_one * eos.isothermal_internal_energy * density; } @@ -145,7 +145,7 @@ gas_pressure_from_internal_energy(float density, float u) { * @return The internal energy \f$u\f$ (which is constant). */ __attribute__((always_inline)) INLINE static float -gas_internal_energy_from_pressure(float density, float pressure) { +gas_internal_energy_from_pressure(const float density, const float pressure) { return eos.isothermal_internal_energy; } @@ -160,7 +160,7 @@ gas_internal_energy_from_pressure(float density, float pressure) { * @param u The internal energy \f$u\f$ */ __attribute__((always_inline)) INLINE static float -gas_soundspeed_from_internal_energy(float density, float u) { +gas_soundspeed_from_internal_energy(const float density, const float u) { return sqrtf(eos.isothermal_internal_energy * hydro_gamma * hydro_gamma_minus_one); @@ -177,7 +177,7 @@ gas_soundspeed_from_internal_energy(float density, float u) { * @param P The pressure \f$P\f$ */ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure( - float density, float P) { + const float density, const float P) { return sqrtf(eos.isothermal_internal_energy * hydro_gamma * hydro_gamma_minus_one); diff --git a/src/equation_of_state/planetary/equation_of_state.h b/src/equation_of_state/planetary/equation_of_state.h index a6d1a4e336a03de108dd6787edb9e66346c1bb43..4a46cadb80cb76fd72aba393026914b94252dbb5 100755 --- a/src/equation_of_state/planetary/equation_of_state.h +++ b/src/equation_of_state/planetary/equation_of_state.h @@ -102,6 +102,10 @@ enum eos_planetary_material_id { eos_planetary_id_Til_basalt = eos_planetary_type_Til * eos_planetary_type_factor + 3, + /*! Tillotson ice */ + eos_planetary_id_Til_ice = + eos_planetary_type_Til * eos_planetary_type_factor + 4, + /* Hubbard & MacFarlane (1980) Uranus/Neptune */ /*! Hydrogen-helium atmosphere */ @@ -134,6 +138,23 @@ enum eos_planetary_material_id { eos_planetary_id_SS08_water = eos_planetary_type_SESAME * eos_planetary_type_factor + 3, + /*! AQUA (Haldemann et al. 2020) SESAME-like water */ + eos_planetary_id_AQUA = + eos_planetary_type_SESAME * eos_planetary_type_factor + 4, + + /*! CMS19 hydrogen (Chabrier et al. 2019) SESAME-like hydrogen */ + eos_planetary_id_CMS19_H = + eos_planetary_type_SESAME * eos_planetary_type_factor + 5, + + /*! CMS19 helium (Chabrier et al. 2019) SESAME-like helium */ + eos_planetary_id_CMS19_He = + eos_planetary_type_SESAME * eos_planetary_type_factor + 6, + + /*! CD21 hydrogen-helium (Chabrier & Debras 2021) SESAME-like H-He mixture + (Y=0.245) */ + eos_planetary_id_CD21_HHe = + eos_planetary_type_SESAME * eos_planetary_type_factor + 7, + /* ANEOS */ /*! ANEOS forsterite (Stewart et al. 2019) -- in SESAME-style tables */ @@ -149,6 +170,10 @@ enum eos_planetary_material_id { eos_planetary_type_ANEOS * eos_planetary_type_factor + 2, }; +/* Base material ID for custom Tillotson EoS */ +#define eos_planetary_Til_custom_base_id \ + (eos_planetary_type_Til * eos_planetary_type_factor + 90) + /* Individual EOS function headers. */ #include "hm80.h" #include "ideal_gas.h" @@ -160,9 +185,11 @@ enum eos_planetary_material_id { */ struct eos_parameters { struct idg_params idg_def; - struct Til_params Til_iron, Til_granite, Til_water, Til_basalt; + struct Til_params Til_iron, Til_granite, Til_water, Til_basalt, Til_ice, + Til_custom[10]; struct HM80_params HM80_HHe, HM80_ice, HM80_rock; - struct SESAME_params SESAME_iron, SESAME_basalt, SESAME_water, SS08_water; + struct SESAME_params SESAME_iron, SESAME_basalt, SESAME_water, SS08_water, + AQUA, CMS19_H, CMS19_He, CD21_HHe; struct SESAME_params ANEOS_forsterite, ANEOS_iron, ANEOS_Fe85Si15; struct SESAME_params custom[10]; }; @@ -223,8 +250,20 @@ gas_internal_energy_from_entropy(float density, float entropy, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_internal_energy_from_entropy(density, entropy, + &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_internal_energy_from_entropy(density, entropy, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -278,6 +317,42 @@ gas_internal_energy_from_entropy(float density, float entropy, &eos.SS08_water); break; + case eos_planetary_id_AQUA: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.AQUA.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_AQUA: 1"); +#endif + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CMS19_H.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CMS19_H: 1"); +#endif + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CMS19_He.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CMS19_He: 1"); +#endif + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CD21_HHe.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CD21_HHe: 1"); +#endif + return SESAME_internal_energy_from_entropy(density, entropy, + &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -372,8 +447,19 @@ __attribute__((always_inline)) INLINE static float gas_pressure_from_entropy( return Til_pressure_from_entropy(density, entropy, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_pressure_from_entropy(density, entropy, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_pressure_from_entropy(density, entropy, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -424,6 +510,22 @@ __attribute__((always_inline)) INLINE static float gas_pressure_from_entropy( &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_pressure_from_entropy(density, entropy, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_pressure_from_entropy(density, entropy, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_pressure_from_entropy(density, entropy, &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_pressure_from_entropy(density, entropy, &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -519,8 +621,19 @@ __attribute__((always_inline)) INLINE static float gas_entropy_from_pressure( return Til_entropy_from_pressure(density, P, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_entropy_from_pressure(density, P, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_entropy_from_pressure(density, P, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -567,6 +680,22 @@ __attribute__((always_inline)) INLINE static float gas_entropy_from_pressure( return SESAME_entropy_from_pressure(density, P, &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_entropy_from_pressure(density, P, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_entropy_from_pressure(density, P, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_entropy_from_pressure(density, P, &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_entropy_from_pressure(density, P, &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -659,8 +788,19 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy( return Til_soundspeed_from_entropy(density, entropy, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_soundspeed_from_entropy(density, entropy, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_soundspeed_from_entropy(density, entropy, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -711,6 +851,24 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy( &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_soundspeed_from_entropy(density, entropy, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_soundspeed_from_entropy(density, entropy, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_soundspeed_from_entropy(density, entropy, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_soundspeed_from_entropy(density, entropy, + &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -805,8 +963,19 @@ gas_entropy_from_internal_energy(float density, float u, return Til_entropy_from_internal_energy(density, u, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_entropy_from_internal_energy(density, u, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_entropy_from_internal_energy(density, u, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -857,6 +1026,22 @@ gas_entropy_from_internal_energy(float density, float u, &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_entropy_from_internal_energy(density, u, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_entropy_from_internal_energy(density, u, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_entropy_from_internal_energy(density, u, &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_entropy_from_internal_energy(density, u, &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -978,11 +1163,26 @@ gas_pressure_from_internal_energy(float density, float u, return Til_pressure_from_internal_energy(density, u, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.Til_ice.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_Til_ice: 1"); +#endif + return Til_pressure_from_internal_energy(density, u, &eos.Til_ice); + break; + default: + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_pressure_from_internal_energy(density, u, + &eos.Til_custom[i_custom]); + } else { #ifdef SWIFT_DEBUG_CHECKS - error("Unknown material ID! mat_id = %d", mat_id); + error("Unknown material ID! mat_id = %d", mat_id); #endif - return -1.f; + return -1.f; + } }; break; @@ -1070,6 +1270,40 @@ gas_pressure_from_internal_energy(float density, float u, &eos.SS08_water); break; + case eos_planetary_id_AQUA: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.AQUA.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_AQUA: 1"); +#endif + return SESAME_pressure_from_internal_energy(density, u, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CMS19_H.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CMS19_H: 1"); +#endif + return SESAME_pressure_from_internal_energy(density, u, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CMS19_He.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CMS19_He: 1"); +#endif + return SESAME_pressure_from_internal_energy(density, u, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: +#ifdef SWIFT_DEBUG_CHECKS + if (eos.CD21_HHe.mat_id != mat_id) + error("EoS not enabled. Please set EoS:planetary_use_CD21_HHe: 1"); +#endif + return SESAME_pressure_from_internal_energy(density, u, + &eos.CD21_HHe); + break; + default: #ifdef SWIFT_DEBUG_CHECKS error("Unknown material ID! mat_id = %d", mat_id); @@ -1200,8 +1434,19 @@ gas_internal_energy_from_pressure(float density, float P, return Til_internal_energy_from_pressure(density, P, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_internal_energy_from_pressure(density, P, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_internal_energy_from_pressure(density, P, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -1252,6 +1497,24 @@ gas_internal_energy_from_pressure(float density, float P, &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_internal_energy_from_pressure(density, P, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_internal_energy_from_pressure(density, P, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_internal_energy_from_pressure(density, P, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_internal_energy_from_pressure(density, P, + &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -1350,8 +1613,19 @@ gas_soundspeed_from_internal_energy(float density, float u, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_soundspeed_from_internal_energy(density, u, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_soundspeed_from_internal_energy( + density, u, &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -1405,6 +1679,25 @@ gas_soundspeed_from_internal_energy(float density, float u, &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_soundspeed_from_internal_energy(density, u, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_soundspeed_from_internal_energy(density, u, + &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -1499,8 +1792,19 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure( return Til_soundspeed_from_pressure(density, P, &eos.Til_basalt); break; + case eos_planetary_id_Til_ice: + return Til_soundspeed_from_pressure(density, P, &eos.Til_ice); + break; + default: - return -1.f; + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_soundspeed_from_pressure(density, P, + &eos.Til_custom[i_custom]); + } else { + return -1.f; + } }; break; @@ -1548,6 +1852,22 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure( return SESAME_soundspeed_from_pressure(density, P, &eos.SS08_water); break; + case eos_planetary_id_AQUA: + return SESAME_soundspeed_from_pressure(density, P, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_soundspeed_from_pressure(density, P, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_soundspeed_from_pressure(density, P, &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_soundspeed_from_pressure(density, P, &eos.CD21_HHe); + break; + default: return -1.f; }; @@ -1591,106 +1911,740 @@ __attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure( } /** - * @brief Initialize the eos parameters + * @brief Returns the temperature given density and internal energy * - * @param e The #eos_parameters - * @param params The parsed parameters + * @param density The density \f$\rho\f$ + * @param u The internal energy \f$u\f$ */ -__attribute__((always_inline)) INLINE static void eos_init( - struct eos_parameters *e, const struct phys_const *phys_const, - const struct unit_system *us, struct swift_params *params) { +__attribute__((always_inline)) INLINE static float +gas_temperature_from_internal_energy(float density, float u, + enum eos_planetary_material_id mat_id) { + const enum eos_planetary_type_id type = + (enum eos_planetary_type_id)(mat_id / eos_planetary_type_factor); - // Prepare any/all requested EoS: Set the parameters and material IDs, load - // tables etc., and convert to internal units + /* Select the material base type */ + switch (type) { - // Ideal gas - if (parser_get_opt_param_int(params, "EoS:planetary_use_idg_def", 0)) { - set_idg_def(&e->idg_def, eos_planetary_id_idg_def); - } + /* Ideal gas EoS */ + case eos_planetary_type_idg: - // Tillotson - if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_iron", 0)) { - set_Til_iron(&e->Til_iron, eos_planetary_id_Til_iron); - convert_units_Til(&e->Til_iron, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_granite", 0)) { - set_Til_granite(&e->Til_granite, eos_planetary_id_Til_granite); - convert_units_Til(&e->Til_granite, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_water", 0)) { - set_Til_water(&e->Til_water, eos_planetary_id_Til_water); - convert_units_Til(&e->Til_water, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_basalt", 0)) { - set_Til_basalt(&e->Til_basalt, eos_planetary_id_Til_basalt); - convert_units_Til(&e->Til_basalt, us); - } + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_idg_def: + return idg_temperature_from_internal_energy(density, u, &eos.idg_def); + break; - // Hubbard & MacFarlane (1980) - if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_HHe", 0)) { - char HM80_HHe_table_file[PARSER_MAX_LINE_SIZE]; - set_HM80_HHe(&e->HM80_HHe, eos_planetary_id_HM80_HHe); - parser_get_param_string(params, "EoS:planetary_HM80_HHe_table_file", - HM80_HHe_table_file); - load_table_HM80(&e->HM80_HHe, HM80_HHe_table_file); - prepare_table_HM80(&e->HM80_HHe); - convert_units_HM80(&e->HM80_HHe, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_ice", 0)) { - char HM80_ice_table_file[PARSER_MAX_LINE_SIZE]; - set_HM80_ice(&e->HM80_ice, eos_planetary_id_HM80_ice); - parser_get_param_string(params, "EoS:planetary_HM80_ice_table_file", - HM80_ice_table_file); - load_table_HM80(&e->HM80_ice, HM80_ice_table_file); - prepare_table_HM80(&e->HM80_ice); - convert_units_HM80(&e->HM80_ice, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_rock", 0)) { - char HM80_rock_table_file[PARSER_MAX_LINE_SIZE]; - set_HM80_rock(&e->HM80_rock, eos_planetary_id_HM80_rock); - parser_get_param_string(params, "EoS:planetary_HM80_rock_table_file", - HM80_rock_table_file); - load_table_HM80(&e->HM80_rock, HM80_rock_table_file); - prepare_table_HM80(&e->HM80_rock); - convert_units_HM80(&e->HM80_rock, us); - } + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; - // SESAME - if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_iron", 0)) { - char SESAME_iron_table_file[PARSER_MAX_LINE_SIZE]; - set_SESAME_iron(&e->SESAME_iron, eos_planetary_id_SESAME_iron); - parser_get_param_string(params, "EoS:planetary_SESAME_iron_table_file", - SESAME_iron_table_file); - load_table_SESAME(&e->SESAME_iron, SESAME_iron_table_file); - prepare_table_SESAME(&e->SESAME_iron); - convert_units_SESAME(&e->SESAME_iron, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_basalt", 0)) { - char SESAME_basalt_table_file[PARSER_MAX_LINE_SIZE]; - set_SESAME_basalt(&e->SESAME_basalt, eos_planetary_id_SESAME_basalt); - parser_get_param_string(params, "EoS:planetary_SESAME_basalt_table_file", - SESAME_basalt_table_file); - load_table_SESAME(&e->SESAME_basalt, SESAME_basalt_table_file); - prepare_table_SESAME(&e->SESAME_basalt); - convert_units_SESAME(&e->SESAME_basalt, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_water", 0)) { - char SESAME_water_table_file[PARSER_MAX_LINE_SIZE]; - set_SESAME_water(&e->SESAME_water, eos_planetary_id_SESAME_water); - parser_get_param_string(params, "EoS:planetary_SESAME_water_table_file", - SESAME_water_table_file); - load_table_SESAME(&e->SESAME_water, SESAME_water_table_file); - prepare_table_SESAME(&e->SESAME_water); - convert_units_SESAME(&e->SESAME_water, us); - } - if (parser_get_opt_param_int(params, "EoS:planetary_use_SS08_water", 0)) { - char SS08_water_table_file[PARSER_MAX_LINE_SIZE]; - set_SS08_water(&e->SS08_water, eos_planetary_id_SS08_water); - parser_get_param_string(params, "EoS:planetary_SS08_water_table_file", - SS08_water_table_file); - load_table_SESAME(&e->SS08_water, SS08_water_table_file); - prepare_table_SESAME(&e->SS08_water); - convert_units_SESAME(&e->SS08_water, us); + /* Tillotson EoS */ + case eos_planetary_type_Til: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_Til_iron: + return Til_temperature_from_internal_energy(density, u, + &eos.Til_iron); + break; + + case eos_planetary_id_Til_granite: + return Til_temperature_from_internal_energy(density, u, + &eos.Til_granite); + break; + + case eos_planetary_id_Til_water: + return Til_temperature_from_internal_energy(density, u, + &eos.Til_water); + break; + + case eos_planetary_id_Til_basalt: + return Til_temperature_from_internal_energy(density, u, + &eos.Til_basalt); + break; + + case eos_planetary_id_Til_ice: + return Til_temperature_from_internal_energy(density, u, &eos.Til_ice); + break; + + default: + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_temperature_from_internal_energy( + density, u, &eos.Til_custom[i_custom]); + } else { + return -1.f; + } + }; + break; + + /* Hubbard & MacFarlane (1980) EoS */ + case eos_planetary_type_HM80: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_HM80_HHe: + return HM80_temperature_from_internal_energy(density, u, + &eos.HM80_HHe); + break; + + case eos_planetary_id_HM80_ice: + return HM80_temperature_from_internal_energy(density, u, + &eos.HM80_ice); + break; + + case eos_planetary_id_HM80_rock: + return HM80_temperature_from_internal_energy(density, u, + &eos.HM80_rock); + break; + + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; + + /* SESAME EoS */ + case eos_planetary_type_SESAME:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_SESAME_iron: + return SESAME_temperature_from_internal_energy(density, u, + &eos.SESAME_iron); + break; + + case eos_planetary_id_SESAME_basalt: + return SESAME_temperature_from_internal_energy(density, u, + &eos.SESAME_basalt); + break; + + case eos_planetary_id_SESAME_water: + return SESAME_temperature_from_internal_energy(density, u, + &eos.SESAME_water); + break; + + case eos_planetary_id_SS08_water: + return SESAME_temperature_from_internal_energy(density, u, + &eos.SS08_water); + break; + + case eos_planetary_id_AQUA: + return SESAME_temperature_from_internal_energy(density, u, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_temperature_from_internal_energy(density, u, + &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_temperature_from_internal_energy(density, u, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_temperature_from_internal_energy(density, u, + &eos.CD21_HHe); + break; + + default: + return -1.f; + }; + break; + + /* ANEOS -- using SESAME-style tables */ + case eos_planetary_type_ANEOS:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_ANEOS_forsterite: + return SESAME_temperature_from_internal_energy(density, u, + &eos.ANEOS_forsterite); + break; + + case eos_planetary_id_ANEOS_iron: + return SESAME_temperature_from_internal_energy(density, u, + &eos.ANEOS_iron); + break; + + case eos_planetary_id_ANEOS_Fe85Si15: + return SESAME_temperature_from_internal_energy(density, u, + &eos.ANEOS_Fe85Si15); + break; + + default: + return -1.f; + }; + break; + + /*! Generic user-provided custom tables */ + case eos_planetary_type_custom: { + const int i_custom = + mat_id - eos_planetary_type_custom * eos_planetary_type_factor; + return SESAME_temperature_from_internal_energy(density, u, + &eos.custom[i_custom]); + break; + } + + default: + return -1.f; + } +} + +/** + * @brief Returns the density given pressure and temperature + * + * @param P The pressure \f$P\f$ + * @param T The temperature \f$T\f$ + */ +__attribute__((always_inline)) INLINE static float +gas_density_from_pressure_and_temperature( + float P, float T, enum eos_planetary_material_id mat_id) { + const enum eos_planetary_type_id type = + (enum eos_planetary_type_id)(mat_id / eos_planetary_type_factor); + + /* Select the material base type */ + switch (type) { + + /* Ideal gas EoS */ + case eos_planetary_type_idg: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_idg_def: + return idg_density_from_pressure_and_temperature(P, T, &eos.idg_def); + break; + + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; + + /* Tillotson EoS */ + case eos_planetary_type_Til: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_Til_iron: + return Til_density_from_pressure_and_temperature(P, T, &eos.Til_iron); + break; + + case eos_planetary_id_Til_granite: + return Til_density_from_pressure_and_temperature(P, T, + &eos.Til_granite); + break; + + case eos_planetary_id_Til_water: + return Til_density_from_pressure_and_temperature(P, T, + &eos.Til_water); + break; + + case eos_planetary_id_Til_basalt: + return Til_density_from_pressure_and_temperature(P, T, + &eos.Til_basalt); + break; + + case eos_planetary_id_Til_ice: + return Til_density_from_pressure_and_temperature(P, T, &eos.Til_ice); + break; + + default: + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_density_from_pressure_and_temperature( + P, T, &eos.Til_custom[i_custom]); + } else { + return -1.f; + } + }; + break; + + /* Hubbard & MacFarlane (1980) EoS */ + case eos_planetary_type_HM80: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_HM80_HHe: + return HM80_density_from_pressure_and_temperature(P, T, + &eos.HM80_HHe); + break; + + case eos_planetary_id_HM80_ice: + return HM80_density_from_pressure_and_temperature(P, T, + &eos.HM80_ice); + break; + + case eos_planetary_id_HM80_rock: + return HM80_density_from_pressure_and_temperature(P, T, + &eos.HM80_rock); + break; + + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; + + /* SESAME EoS */ + case eos_planetary_type_SESAME:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_SESAME_iron: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.SESAME_iron); + break; + + case eos_planetary_id_SESAME_basalt: + return SESAME_density_from_pressure_and_temperature( + P, T, &eos.SESAME_basalt); + break; + + case eos_planetary_id_SESAME_water: + return SESAME_density_from_pressure_and_temperature( + P, T, &eos.SESAME_water); + break; + + case eos_planetary_id_SS08_water: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.SS08_water); + break; + + case eos_planetary_id_AQUA: + return SESAME_density_from_pressure_and_temperature(P, T, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.CD21_HHe); + break; + + default: + return -1.f; + }; + break; + + /* ANEOS -- using SESAME-style tables */ + case eos_planetary_type_ANEOS:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_ANEOS_forsterite: + return SESAME_density_from_pressure_and_temperature( + P, T, &eos.ANEOS_forsterite); + break; + + case eos_planetary_id_ANEOS_iron: + return SESAME_density_from_pressure_and_temperature(P, T, + &eos.ANEOS_iron); + break; + + case eos_planetary_id_ANEOS_Fe85Si15: + return SESAME_density_from_pressure_and_temperature( + P, T, &eos.ANEOS_Fe85Si15); + break; + + default: + return -1.f; + }; + break; + + /*! Generic user-provided custom tables */ + case eos_planetary_type_custom: { + const int i_custom = + mat_id - eos_planetary_type_custom * eos_planetary_type_factor; + return SESAME_density_from_pressure_and_temperature( + P, T, &eos.custom[i_custom]); + break; + } + + default: + return -1.f; + } +} + +/** + * @brief Returns the density given pressure and internal energy + * + * @param P The pressure \f$P\f$ + * @param T The temperature \f$T\f$ + */ +__attribute__((always_inline)) INLINE static float +gas_density_from_pressure_and_internal_energy( + float P, float u, float rho_ref, float rho_sph, + enum eos_planetary_material_id mat_id) { + const enum eos_planetary_type_id type = + (enum eos_planetary_type_id)(mat_id / eos_planetary_type_factor); + + /* Select the material base type */ + switch (type) { + + /* Ideal gas EoS */ + case eos_planetary_type_idg: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_idg_def: + return idg_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.idg_def); + break; + + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; + + /* Tillotson EoS */ + case eos_planetary_type_Til: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_Til_iron: + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_iron); + break; + + case eos_planetary_id_Til_granite: + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_granite); + break; + + case eos_planetary_id_Til_water: + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_water); + break; + + case eos_planetary_id_Til_basalt: + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_basalt); + break; + + case eos_planetary_id_Til_ice: + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_ice); + break; + + default: + // Custom user-provided Tillotson + if (mat_id >= eos_planetary_Til_custom_base_id) { + const int i_custom = mat_id - eos_planetary_Til_custom_base_id; + return Til_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.Til_custom[i_custom]); + } else { + return -1.f; + } + }; + break; + + /* Hubbard & MacFarlane (1980) EoS */ + case eos_planetary_type_HM80: + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_HM80_HHe: + return HM80_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.HM80_HHe); + break; + + case eos_planetary_id_HM80_ice: + return HM80_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.HM80_ice); + break; + + case eos_planetary_id_HM80_rock: + return HM80_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.HM80_rock); + break; + + default: +#ifdef SWIFT_DEBUG_CHECKS + error("Unknown material ID! mat_id = %d", mat_id); +#endif + return -1.f; + }; + break; + + /* SESAME EoS */ + case eos_planetary_type_SESAME:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_SESAME_iron: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.SESAME_iron); + break; + + case eos_planetary_id_SESAME_basalt: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.SESAME_basalt); + break; + + case eos_planetary_id_SESAME_water: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.SESAME_water); + break; + + case eos_planetary_id_SS08_water: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.SS08_water); + break; + + case eos_planetary_id_AQUA: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.AQUA); + break; + + case eos_planetary_id_CMS19_H: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.CMS19_H); + break; + + case eos_planetary_id_CMS19_He: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.CMS19_He); + break; + + case eos_planetary_id_CD21_HHe: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.CD21_HHe); + break; + + default: + return -1.f; + }; + break; + + /* ANEOS -- using SESAME-style tables */ + case eos_planetary_type_ANEOS:; + + /* Select the material of this type */ + switch (mat_id) { + case eos_planetary_id_ANEOS_forsterite: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.ANEOS_forsterite); + break; + + case eos_planetary_id_ANEOS_iron: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.ANEOS_iron); + break; + + case eos_planetary_id_ANEOS_Fe85Si15: + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.ANEOS_Fe85Si15); + break; + + default: + return -1.f; + }; + break; + + /*! Generic user-provided custom tables */ + case eos_planetary_type_custom: { + const int i_custom = + mat_id - eos_planetary_type_custom * eos_planetary_type_factor; + return SESAME_density_from_pressure_and_internal_energy( + P, u, rho_ref, rho_sph, &eos.custom[i_custom]); + break; + } + + default: + return -1.f; + } +} + +/** + * @brief Initialize the eos parameters + * + * @param e The #eos_parameters + * @param params The parsed parameters + */ +__attribute__((always_inline)) INLINE static void eos_init( + struct eos_parameters *e, const struct phys_const *phys_const, + const struct unit_system *us, struct swift_params *params) { + + // Prepare any/all requested EoS: Set the parameters and material IDs, load + // tables etc., and convert to internal units + + // Ideal gas + if (parser_get_opt_param_int(params, "EoS:planetary_use_idg_def", 0)) { + set_idg_def(&e->idg_def, eos_planetary_id_idg_def); + } + + // Tillotson + if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_iron", 0)) { + set_Til_iron(&e->Til_iron, eos_planetary_id_Til_iron); + set_Til_u_cold(&e->Til_iron, eos_planetary_id_Til_iron); + convert_units_Til(&e->Til_iron, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_granite", 0)) { + set_Til_granite(&e->Til_granite, eos_planetary_id_Til_granite); + set_Til_u_cold(&e->Til_granite, eos_planetary_id_Til_granite); + convert_units_Til(&e->Til_granite, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_water", 0)) { + set_Til_water(&e->Til_water, eos_planetary_id_Til_water); + set_Til_u_cold(&e->Til_water, eos_planetary_id_Til_water); + convert_units_Til(&e->Til_water, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_basalt", 0)) { + set_Til_basalt(&e->Til_basalt, eos_planetary_id_Til_basalt); + set_Til_u_cold(&e->Til_basalt, eos_planetary_id_Til_basalt); + convert_units_Til(&e->Til_basalt, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_Til_ice", 0)) { + set_Til_ice(&e->Til_ice, eos_planetary_id_Til_ice); + set_Til_u_cold(&e->Til_ice, eos_planetary_id_Til_ice); + convert_units_Til(&e->Til_ice, us); + } + + // Custom user-provided Tillotson + for (int i_custom = 0; i_custom <= 9; i_custom++) { + char param_name[PARSER_MAX_LINE_SIZE]; + sprintf(param_name, "EoS:planetary_use_Til_custom_%d", i_custom); + if (parser_get_opt_param_int(params, param_name, 0)) { + char Til_custom_file[PARSER_MAX_LINE_SIZE]; + int mat_id = eos_planetary_Til_custom_base_id + i_custom; + + sprintf(param_name, "EoS:planetary_Til_custom_%d_param_file", i_custom); + parser_get_param_string(params, param_name, Til_custom_file); + + set_Til_custom(&e->Til_custom[i_custom], + (enum eos_planetary_material_id)mat_id, Til_custom_file); + set_Til_u_cold(&e->Til_custom[i_custom], + (enum eos_planetary_material_id)mat_id); + convert_units_Til(&e->Til_custom[i_custom], us); + } + } + + // Hubbard & MacFarlane (1980) + if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_HHe", 0)) { + char HM80_HHe_table_file[PARSER_MAX_LINE_SIZE]; + set_HM80_HHe(&e->HM80_HHe, eos_planetary_id_HM80_HHe); + parser_get_param_string(params, "EoS:planetary_HM80_HHe_table_file", + HM80_HHe_table_file); + load_table_HM80(&e->HM80_HHe, HM80_HHe_table_file); + prepare_table_HM80(&e->HM80_HHe); + convert_units_HM80(&e->HM80_HHe, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_ice", 0)) { + char HM80_ice_table_file[PARSER_MAX_LINE_SIZE]; + set_HM80_ice(&e->HM80_ice, eos_planetary_id_HM80_ice); + parser_get_param_string(params, "EoS:planetary_HM80_ice_table_file", + HM80_ice_table_file); + load_table_HM80(&e->HM80_ice, HM80_ice_table_file); + prepare_table_HM80(&e->HM80_ice); + convert_units_HM80(&e->HM80_ice, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80_rock", 0)) { + char HM80_rock_table_file[PARSER_MAX_LINE_SIZE]; + set_HM80_rock(&e->HM80_rock, eos_planetary_id_HM80_rock); + parser_get_param_string(params, "EoS:planetary_HM80_rock_table_file", + HM80_rock_table_file); + load_table_HM80(&e->HM80_rock, HM80_rock_table_file); + prepare_table_HM80(&e->HM80_rock); + convert_units_HM80(&e->HM80_rock, us); + } + + // SESAME + if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_iron", 0)) { + char SESAME_iron_table_file[PARSER_MAX_LINE_SIZE]; + set_SESAME_iron(&e->SESAME_iron, eos_planetary_id_SESAME_iron); + parser_get_param_string(params, "EoS:planetary_SESAME_iron_table_file", + SESAME_iron_table_file); + load_table_SESAME(&e->SESAME_iron, SESAME_iron_table_file); + prepare_table_SESAME(&e->SESAME_iron); + convert_units_SESAME(&e->SESAME_iron, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_basalt", 0)) { + char SESAME_basalt_table_file[PARSER_MAX_LINE_SIZE]; + set_SESAME_basalt(&e->SESAME_basalt, eos_planetary_id_SESAME_basalt); + parser_get_param_string(params, "EoS:planetary_SESAME_basalt_table_file", + SESAME_basalt_table_file); + load_table_SESAME(&e->SESAME_basalt, SESAME_basalt_table_file); + prepare_table_SESAME(&e->SESAME_basalt); + convert_units_SESAME(&e->SESAME_basalt, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME_water", 0)) { + char SESAME_water_table_file[PARSER_MAX_LINE_SIZE]; + set_SESAME_water(&e->SESAME_water, eos_planetary_id_SESAME_water); + parser_get_param_string(params, "EoS:planetary_SESAME_water_table_file", + SESAME_water_table_file); + load_table_SESAME(&e->SESAME_water, SESAME_water_table_file); + prepare_table_SESAME(&e->SESAME_water); + convert_units_SESAME(&e->SESAME_water, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_SS08_water", 0)) { + char SS08_water_table_file[PARSER_MAX_LINE_SIZE]; + set_SS08_water(&e->SS08_water, eos_planetary_id_SS08_water); + parser_get_param_string(params, "EoS:planetary_SS08_water_table_file", + SS08_water_table_file); + load_table_SESAME(&e->SS08_water, SS08_water_table_file); + prepare_table_SESAME(&e->SS08_water); + convert_units_SESAME(&e->SS08_water, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_AQUA", 0)) { + char AQUA_table_file[PARSER_MAX_LINE_SIZE]; + set_AQUA(&e->AQUA, eos_planetary_id_AQUA); + parser_get_param_string(params, "EoS:planetary_AQUA_table_file", + AQUA_table_file); + load_table_SESAME(&e->AQUA, AQUA_table_file); + prepare_table_SESAME(&e->AQUA); + convert_units_SESAME(&e->AQUA, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_CMS19_H", 0)) { + char CMS19_H_table_file[PARSER_MAX_LINE_SIZE]; + set_CMS19_H(&e->CMS19_H, eos_planetary_id_CMS19_H); + parser_get_param_string(params, "EoS:planetary_CMS19_H_table_file", + CMS19_H_table_file); + load_table_SESAME(&e->CMS19_H, CMS19_H_table_file); + prepare_table_SESAME(&e->CMS19_H); + convert_units_SESAME(&e->CMS19_H, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_CMS19_He", 0)) { + char CMS19_He_table_file[PARSER_MAX_LINE_SIZE]; + set_CMS19_He(&e->CMS19_He, eos_planetary_id_CMS19_He); + parser_get_param_string(params, "EoS:planetary_CMS19_He_table_file", + CMS19_He_table_file); + load_table_SESAME(&e->CMS19_He, CMS19_He_table_file); + prepare_table_SESAME(&e->CMS19_He); + convert_units_SESAME(&e->CMS19_He, us); + } + if (parser_get_opt_param_int(params, "EoS:planetary_use_CD21_HHe", 0)) { + char CD21_HHe_table_file[PARSER_MAX_LINE_SIZE]; + set_CD21_HHe(&e->CD21_HHe, eos_planetary_id_CD21_HHe); + parser_get_param_string(params, "EoS:planetary_CD21_HHe_table_file", + CD21_HHe_table_file); + load_table_SESAME(&e->CD21_HHe, CD21_HHe_table_file); + prepare_table_SESAME(&e->CD21_HHe); + convert_units_SESAME(&e->CD21_HHe, us); } // ANEOS -- using SESAME-style tables diff --git a/src/equation_of_state/planetary/hm80.h b/src/equation_of_state/planetary/hm80.h index d969e86e88d5807e514fad8606d4a63188e99a5d..893ef60afa9b07f37e94367824d25b8f3fddc06b 100644 --- a/src/equation_of_state/planetary/hm80.h +++ b/src/equation_of_state/planetary/hm80.h @@ -179,7 +179,7 @@ INLINE static void convert_units_HM80(struct HM80_params *mat, // gas_internal_energy_from_entropy INLINE static float HM80_internal_energy_from_entropy( - float density, float entropy, const struct HM80_params *mat) { + const float density, const float entropy, const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); @@ -187,7 +187,8 @@ INLINE static float HM80_internal_energy_from_entropy( } // gas_pressure_from_entropy -INLINE static float HM80_pressure_from_entropy(float density, float entropy, +INLINE static float HM80_pressure_from_entropy(const float density, + const float entropy, const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); @@ -196,7 +197,8 @@ INLINE static float HM80_pressure_from_entropy(float density, float entropy, } // gas_entropy_from_pressure -INLINE static float HM80_entropy_from_pressure(float density, float pressure, +INLINE static float HM80_entropy_from_pressure(const float density, + const float pressure, const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); @@ -206,7 +208,7 @@ INLINE static float HM80_entropy_from_pressure(float density, float pressure, // gas_soundspeed_from_entropy INLINE static float HM80_soundspeed_from_entropy( - float density, float entropy, const struct HM80_params *mat) { + const float density, const float entropy, const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); @@ -215,29 +217,25 @@ INLINE static float HM80_soundspeed_from_entropy( // gas_entropy_from_internal_energy INLINE static float HM80_entropy_from_internal_energy( - float density, float u, const struct HM80_params *mat) { + const float density, const float u, const struct HM80_params *mat) { return 0.f; } // gas_pressure_from_internal_energy INLINE static float HM80_pressure_from_internal_energy( - float density, float u, const struct HM80_params *mat) { - - float log_P, log_P_1, log_P_2, log_P_3, log_P_4; + const float density, const float u, const struct HM80_params *mat) { if (u <= 0.f) { return 0.f; } - int idx_rho, idx_u; - float intp_rho, intp_u; const float log_rho = logf(density); const float log_u = logf(u); // 2D interpolation (bilinear with log(rho), log(u)) to find P(rho, u) - idx_rho = floor((log_rho - mat->log_rho_min) * mat->inv_log_rho_step); - idx_u = floor((log_u - mat->log_u_min) * mat->inv_log_u_step); + int idx_rho = floor((log_rho - mat->log_rho_min) * mat->inv_log_rho_step); + int idx_u = floor((log_u - mat->log_u_min) * mat->inv_log_u_step); // If outside the table then extrapolate from the edge and edge-but-one values if (idx_rho <= -1) { @@ -251,26 +249,31 @@ INLINE static float HM80_pressure_from_internal_energy( idx_u = mat->num_u - 2; } - intp_rho = (log_rho - mat->log_rho_min - idx_rho * mat->log_rho_step) * - mat->inv_log_rho_step; - intp_u = + const float intp_rho = + (log_rho - mat->log_rho_min - idx_rho * mat->log_rho_step) * + mat->inv_log_rho_step; + const float intp_u = (log_u - mat->log_u_min - idx_u * mat->log_u_step) * mat->inv_log_u_step; // Table values - log_P_1 = mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u]; - log_P_2 = mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u + 1]; - log_P_3 = mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u]; - log_P_4 = mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u + 1]; - - log_P = (1.f - intp_rho) * ((1.f - intp_u) * log_P_1 + intp_u * log_P_2) + - intp_rho * ((1.f - intp_u) * log_P_3 + intp_u * log_P_4); + const float log_P_1 = mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u]; + const float log_P_2 = + mat->table_log_P_rho_u[idx_rho * mat->num_u + idx_u + 1]; + const float log_P_3 = + mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u]; + const float log_P_4 = + mat->table_log_P_rho_u[(idx_rho + 1) * mat->num_u + idx_u + 1]; + + const float log_P = + (1.f - intp_rho) * ((1.f - intp_u) * log_P_1 + intp_u * log_P_2) + + intp_rho * ((1.f - intp_u) * log_P_3 + intp_u * log_P_4); return expf(log_P); } // gas_internal_energy_from_pressure INLINE static float HM80_internal_energy_from_pressure( - float density, float P, const struct HM80_params *mat) { + const float density, const float P, const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); @@ -279,9 +282,9 @@ INLINE static float HM80_internal_energy_from_pressure( // gas_soundspeed_from_internal_energy INLINE static float HM80_soundspeed_from_internal_energy( - float density, float u, const struct HM80_params *mat) { + const float density, const float u, const struct HM80_params *mat) { - float c, P; + float c; // Bulk modulus if (mat->bulk_mod != 0) { @@ -289,10 +292,10 @@ INLINE static float HM80_soundspeed_from_internal_energy( } // Ideal gas else { - P = HM80_pressure_from_internal_energy(density, u, mat); + const float P = HM80_pressure_from_internal_energy(density, u, mat); c = sqrtf(hydro_gamma * P / density); - if (c <= 0) { + if (c <= 0.f) { c = sqrtf(hydro_gamma * mat->P_min_for_c_min / density); } } @@ -302,7 +305,35 @@ INLINE static float HM80_soundspeed_from_internal_energy( // gas_soundspeed_from_pressure INLINE static float HM80_soundspeed_from_pressure( - float density, float P, const struct HM80_params *mat) { + const float density, const float P, const struct HM80_params *mat) { + + error("This EOS function is not yet implemented!"); + + return 0.f; +} + +// gas_entropy_from_internal_energy +INLINE static float HM80_temperature_from_internal_energy( + const float density, const float u, const struct HM80_params *mat) { + + error("This EOS function is not yet implemented!"); + + return 0.f; +} + +// gas_density_from_pressure_and_temperature +INLINE static float HM80_density_from_pressure_and_temperature( + const float P, const float T, const struct HM80_params *mat) { + + error("This EOS function is not yet implemented!"); + + return 0.f; +} + +// gas_density_from_pressure_and_internal_energy +INLINE static float HM80_density_from_pressure_and_internal_energy( + const float P, const float u, const float rho_ref, const float rho_sph, + const struct HM80_params *mat) { error("This EOS function is not yet implemented!"); diff --git a/src/equation_of_state/planetary/ideal_gas.h b/src/equation_of_state/planetary/ideal_gas.h index c6da2445dad98d37cd03caa444efb9744f80d238..a2fe001e5f92791854606d2c347ee6fbac1fd88e 100644 --- a/src/equation_of_state/planetary/ideal_gas.h +++ b/src/equation_of_state/planetary/ideal_gas.h @@ -58,7 +58,7 @@ INLINE static void set_idg_def(struct idg_params *mat, * @param entropy The entropy \f$A\f$. */ INLINE static float idg_internal_energy_from_entropy( - float density, float entropy, const struct idg_params *mat) { + const float density, const float entropy, const struct idg_params *mat) { return entropy * powf(density, mat->gamma - 1.f) * mat->one_over_gamma_minus_one; @@ -72,7 +72,8 @@ INLINE static float idg_internal_energy_from_entropy( * @param density The density \f$\rho\f$. * @param entropy The entropy \f$A\f$. */ -INLINE static float idg_pressure_from_entropy(float density, float entropy, +INLINE static float idg_pressure_from_entropy(const float density, + const float entropy, const struct idg_params *mat) { return entropy * powf(density, mat->gamma); @@ -87,7 +88,8 @@ INLINE static float idg_pressure_from_entropy(float density, float entropy, * @param pressure The pressure \f$P\f$. * @return The entropy \f$A\f$. */ -INLINE static float idg_entropy_from_pressure(float density, float pressure, +INLINE static float idg_entropy_from_pressure(const float density, + const float pressure, const struct idg_params *mat) { return pressure * powf(density, -mat->gamma); @@ -101,7 +103,8 @@ INLINE static float idg_entropy_from_pressure(float density, float pressure, * @param density The density \f$\rho\f$. * @param entropy The entropy \f$A\f$. */ -INLINE static float idg_soundspeed_from_entropy(float density, float entropy, +INLINE static float idg_soundspeed_from_entropy(const float density, + const float entropy, const struct idg_params *mat) { return sqrtf(mat->gamma * powf(density, mat->gamma - 1.f) * entropy); @@ -116,7 +119,7 @@ INLINE static float idg_soundspeed_from_entropy(float density, float entropy, * @param u The internal energy \f$u\f$ */ INLINE static float idg_entropy_from_internal_energy( - float density, float u, const struct idg_params *mat) { + const float density, const float u, const struct idg_params *mat) { return (mat->gamma - 1.f) * u * powf(density, 1.f - mat->gamma); } @@ -130,7 +133,7 @@ INLINE static float idg_entropy_from_internal_energy( * @param u The internal energy \f$u\f$ */ INLINE static float idg_pressure_from_internal_energy( - float density, float u, const struct idg_params *mat) { + const float density, const float u, const struct idg_params *mat) { return (mat->gamma - 1.f) * u * density; } @@ -145,7 +148,7 @@ INLINE static float idg_pressure_from_internal_energy( * @return The internal energy \f$u\f$. */ INLINE static float idg_internal_energy_from_pressure( - float density, float pressure, const struct idg_params *mat) { + const float density, const float pressure, const struct idg_params *mat) { return mat->one_over_gamma_minus_one * pressure / density; } @@ -159,7 +162,7 @@ INLINE static float idg_internal_energy_from_pressure( * @param u The internal energy \f$u\f$ */ INLINE static float idg_soundspeed_from_internal_energy( - float density, float u, const struct idg_params *mat) { + const float density, const float u, const struct idg_params *mat) { return sqrtf(u * mat->gamma * (mat->gamma - 1.f)); } @@ -172,10 +175,37 @@ INLINE static float idg_soundspeed_from_internal_energy( * @param density The density \f$\rho\f$ * @param P The pressure \f$P\f$ */ -INLINE static float idg_soundspeed_from_pressure(float density, float P, +INLINE static float idg_soundspeed_from_pressure(const float density, + const float P, const struct idg_params *mat) { return sqrtf(mat->gamma * P / density); } +// gas_temperature_from_internal_energy +INLINE static float idg_temperature_from_internal_energy( + const float density, const float u, const struct idg_params *mat) { + + error("This EOS function is not yet implemented!"); + + return 0.f; +} + +// gas_density_from_pressure_and_temperature +INLINE static float idg_density_from_pressure_and_temperature( + const float P, const float T, const struct idg_params *mat) { + + error("This EOS function is not yet implemented!"); + + return 0.f; +} + +// gas_density_from_pressure_and_internal_energy +INLINE static float idg_density_from_pressure_and_internal_energy( + const float P, const float u, const float rho_ref, const float rho_sph, + const struct idg_params *mat) { + + return mat->one_over_gamma_minus_one * P / u; +} + #endif /* SWIFT_IDEAL_GAS_EQUATION_OF_STATE_H */ diff --git a/src/equation_of_state/planetary/sesame.h b/src/equation_of_state/planetary/sesame.h old mode 100755 new mode 100644 index e86111664cce4e98625629a24d2729ddf5e67f8d..cb4b8cccbcaaa4507727f1a4a3a61caaf66501ac --- a/src/equation_of_state/planetary/sesame.h +++ b/src/equation_of_state/planetary/sesame.h @@ -43,6 +43,7 @@ // SESAME parameters struct SESAME_params { float *table_log_rho; + float *table_log_T; float *table_log_u_rho_T; float *table_P_rho_T; float *table_c_rho_T; @@ -77,6 +78,30 @@ INLINE static void set_SS08_water(struct SESAME_params *mat, mat->mat_id = mat_id; mat->version_date = 20220714; } +INLINE static void set_AQUA(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // Haldemann et al. (2020) + mat->mat_id = mat_id; + mat->version_date = 20220714; +} +INLINE static void set_CMS19_H(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // Chabrier et al. (2019) + mat->mat_id = mat_id; + mat->version_date = 20220905; +} +INLINE static void set_CMS19_He(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // Chabrier et al. (2019) + mat->mat_id = mat_id; + mat->version_date = 20220905; +} +INLINE static void set_CD21_HHe(struct SESAME_params *mat, + enum eos_planetary_material_id mat_id) { + // Chabrier & Debras (2021) + mat->mat_id = mat_id; + mat->version_date = 20220905; +} INLINE static void set_ANEOS_forsterite(struct SESAME_params *mat, enum eos_planetary_material_id mat_id) { // Stewart et al. (2019) @@ -176,6 +201,7 @@ INLINE static void load_table_SESAME(struct SESAME_params *mat, // Allocate table memory mat->table_log_rho = (float *)malloc(mat->num_rho * sizeof(float)); + mat->table_log_T = (float *)malloc(mat->num_T * sizeof(float)); mat->table_log_u_rho_T = (float *)malloc(mat->num_rho * mat->num_T * sizeof(float)); mat->table_P_rho_T = @@ -197,10 +223,16 @@ INLINE static void load_table_SESAME(struct SESAME_params *mat, } } - // Temperatures (ignored) + // Temperatures (not log yet) for (int i_T = -1; i_T < mat->num_T; i_T++) { - c = fscanf(f, "%f", &ignore); - if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); + // Ignore the first elements of rho = 0, T = 0 + if (i_T == -1) { + c = fscanf(f, "%f", &ignore); + if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); + } else { + c = fscanf(f, "%f", &mat->table_log_T[i_T]); + if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); + } } // Sp. int. energies (not log yet), pressures, sound speeds, and sp. @@ -232,6 +264,10 @@ INLINE static void prepare_table_SESAME(struct SESAME_params *mat) { for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { mat->table_log_rho[i_rho] = logf(mat->table_log_rho[i_rho]); } + // Convert temperatures to log(temperature) + for (int i_T = 0; i_T < mat->num_T; i_T++) { + mat->table_log_T[i_T] = logf(mat->table_log_T[i_T]); + } // Initialise tiny values mat->u_tiny = FLT_MAX; @@ -297,6 +333,11 @@ INLINE static void prepare_table_SESAME(struct SESAME_params *mat) { mat->table_log_s_rho_T[i_rho * mat->num_T + i_T] = logf(mat->table_log_s_rho_T[i_rho * mat->num_T + i_T]); + + // Ensure P > 0 + if (mat->table_P_rho_T[i_rho * mat->num_T + i_T] <= 0) { + mat->table_P_rho_T[i_rho * mat->num_T + i_T] = mat->P_tiny; + } } } } @@ -316,6 +357,13 @@ INLINE static void convert_units_SESAME(struct SESAME_params *mat, units_cgs_conversion_factor(us, UNIT_CONV_DENSITY)); } + // Temperatures (log) + for (int i_T = 0; i_T < mat->num_T; i_T++) { + mat->table_log_T[i_T] += + logf(units_cgs_conversion_factor(&si, UNIT_CONV_TEMPERATURE) / + units_cgs_conversion_factor(us, UNIT_CONV_TEMPERATURE)); + } + // Sp. int. energies (log), pressures, sound speeds, and sp. entropies for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { for (int i_T = 0; i_T < mat->num_T; i_T++) { @@ -352,28 +400,26 @@ INLINE static void convert_units_SESAME(struct SESAME_params *mat, // gas_internal_energy_from_entropy INLINE static float SESAME_internal_energy_from_entropy( - float density, float entropy, const struct SESAME_params *mat) { - - float u, log_u_1, log_u_2, log_u_3, log_u_4; + const float density, const float entropy, const struct SESAME_params *mat) { + // Return zero if entropy is zero if (entropy <= 0.f) { return 0.f; } - int idx_rho, idx_s_1, idx_s_2; - float intp_rho, intp_s_1, intp_s_2; const float log_rho = logf(density); const float log_s = logf(entropy); - // 2D interpolation (bilinear with log(rho), log(s)) to find u(rho, s)) + // 2D interpolation (bilinear with log(rho), log(s) to find u(rho, s)) + // Density index - idx_rho = + int idx_rho = find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); // Sp. entropy at this and the next density (in relevant slice of s array) - idx_s_1 = find_value_in_monot_incr_array( + int idx_s_1 = find_value_in_monot_incr_array( log_s, mat->table_log_s_rho_T + idx_rho * mat->num_T, mat->num_T); - idx_s_2 = find_value_in_monot_incr_array( + int idx_s_2 = find_value_in_monot_incr_array( log_s, mat->table_log_s_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); // If outside the table then extrapolate from the edge and edge-but-one values @@ -394,6 +440,7 @@ INLINE static float SESAME_internal_energy_from_entropy( } // Check for duplicates in SESAME tables before interpolation + float intp_rho, intp_s_1, intp_s_2; if (mat->table_log_rho[idx_rho + 1] != mat->table_log_rho[idx_rho]) { intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); @@ -420,10 +467,13 @@ INLINE static float SESAME_internal_energy_from_entropy( } // Table values - log_u_1 = mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_s_1]; - log_u_2 = mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_s_1 + 1]; - log_u_3 = mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_s_2]; - log_u_4 = mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_s_2 + 1]; + const float log_u_1 = mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_s_1]; + const float log_u_2 = + mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_s_1 + 1]; + const float log_u_3 = + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_s_2]; + const float log_u_4 = + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_s_2 + 1]; // If below the minimum s at this rho then just use the lowest table values if ((idx_rho > 0.f) && ((intp_s_1 < 0.f) || (intp_s_2 < 0.f) || @@ -433,18 +483,17 @@ INLINE static float SESAME_internal_energy_from_entropy( } // Interpolate with the log values - u = (1.f - intp_rho) * ((1.f - intp_s_1) * log_u_1 + intp_s_1 * log_u_2) + + const float u = + (1.f - intp_rho) * ((1.f - intp_s_1) * log_u_1 + intp_s_1 * log_u_2) + intp_rho * ((1.f - intp_s_2) * log_u_3 + intp_s_2 * log_u_4); // Convert back from log - u = expf(u); - - return u; + return expf(u); } // gas_pressure_from_entropy INLINE static float SESAME_pressure_from_entropy( - float density, float entropy, const struct SESAME_params *mat) { + const float density, const float entropy, const struct SESAME_params *mat) { error("This EOS function is not yet implemented!"); @@ -453,7 +502,8 @@ INLINE static float SESAME_pressure_from_entropy( // gas_entropy_from_pressure INLINE static float SESAME_entropy_from_pressure( - float density, float pressure, const struct SESAME_params *mat) { + const float density, const float pressure, + const struct SESAME_params *mat) { error("This EOS function is not yet implemented!"); @@ -462,7 +512,7 @@ INLINE static float SESAME_entropy_from_pressure( // gas_soundspeed_from_entropy INLINE static float SESAME_soundspeed_from_entropy( - float density, float entropy, const struct SESAME_params *mat) { + const float density, const float entropy, const struct SESAME_params *mat) { error("This EOS function is not yet implemented!"); @@ -471,35 +521,32 @@ INLINE static float SESAME_soundspeed_from_entropy( // gas_entropy_from_internal_energy INLINE static float SESAME_entropy_from_internal_energy( - float density, float u, const struct SESAME_params *mat) { + const float density, const float u, const struct SESAME_params *mat) { return 0.f; } // gas_pressure_from_internal_energy INLINE static float SESAME_pressure_from_internal_energy( - float density, float u, const struct SESAME_params *mat) { - - float P, P_1, P_2, P_3, P_4; + const float density, const float u, const struct SESAME_params *mat) { if (u <= 0.f) { return 0.f; } - int idx_rho, idx_u_1, idx_u_2; - float intp_rho, intp_u_1, intp_u_2; const float log_rho = logf(density); const float log_u = logf(u); - // 2D interpolation (bilinear with log(rho), log(u)) to find P(rho, u)) + // 2D interpolation (bilinear with log(rho), log(u) to find P(rho, u)) + // Density index - idx_rho = + int idx_rho = find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); // Sp. int. energy at this and the next density (in relevant slice of u array) - idx_u_1 = find_value_in_monot_incr_array( + int idx_u_1 = find_value_in_monot_incr_array( log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); - idx_u_2 = find_value_in_monot_incr_array( + int idx_u_2 = find_value_in_monot_incr_array( log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); // If outside the table then extrapolate from the edge and edge-but-one values @@ -520,18 +567,19 @@ INLINE static float SESAME_pressure_from_internal_energy( } // Check for duplicates in SESAME tables before interpolation + float intp_rho, intp_u_1, intp_u_2; + const int idx_u_rho_T = idx_rho * mat->num_T + idx_u_1; if (mat->table_log_rho[idx_rho + 1] != mat->table_log_rho[idx_rho]) { intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); } else { intp_rho = 1.f; } - if (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] != - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) { - intp_u_1 = - (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / - (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + if (mat->table_log_u_rho_T[idx_u_rho_T + 1] != + mat->table_log_u_rho_T[idx_u_rho_T]) { + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_u_rho_T]) / + (mat->table_log_u_rho_T[idx_u_rho_T + 1] - + mat->table_log_u_rho_T[idx_u_rho_T]); } else { intp_u_1 = 1.f; } @@ -546,10 +594,10 @@ INLINE static float SESAME_pressure_from_internal_energy( } // Table values - P_1 = mat->table_P_rho_T[idx_rho * mat->num_T + idx_u_1]; - P_2 = mat->table_P_rho_T[idx_rho * mat->num_T + idx_u_1 + 1]; - P_3 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; - P_4 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + float P_1 = mat->table_P_rho_T[idx_u_rho_T]; + float P_2 = mat->table_P_rho_T[idx_u_rho_T + 1]; + float P_3 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + float P_4 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; // If below the minimum u at this rho then just use the lowest table values if ((idx_rho > 0.f) && @@ -582,19 +630,18 @@ INLINE static float SESAME_pressure_from_internal_energy( P_2 = logf(P_2); P_3 = logf(P_3); P_4 = logf(P_4); + const float P_1_2 = (1.f - intp_u_1) * P_1 + intp_u_1 * P_2; + const float P_3_4 = (1.f - intp_u_2) * P_3 + intp_u_2 * P_4; - P = (1.f - intp_rho) * ((1.f - intp_u_1) * P_1 + intp_u_1 * P_2) + - intp_rho * ((1.f - intp_u_2) * P_3 + intp_u_2 * P_4); + const float P = (1.f - intp_rho) * P_1_2 + intp_rho * P_3_4; // Convert back from log - P = expf(P); - - return P; + return expf(P); } // gas_internal_energy_from_pressure INLINE static float SESAME_internal_energy_from_pressure( - float density, float P, const struct SESAME_params *mat) { + const float density, const float P, const struct SESAME_params *mat) { error("This EOS function is not yet implemented!"); @@ -603,28 +650,26 @@ INLINE static float SESAME_internal_energy_from_pressure( // gas_soundspeed_from_internal_energy INLINE static float SESAME_soundspeed_from_internal_energy( - float density, float u, const struct SESAME_params *mat) { - - float c, c_1, c_2, c_3, c_4; + const float density, const float u, const struct SESAME_params *mat) { + // Return zero if internal energy is non-positive if (u <= 0.f) { return 0.f; } - int idx_rho, idx_u_1, idx_u_2; - float intp_rho, intp_u_1, intp_u_2; const float log_rho = logf(density); const float log_u = logf(u); - // 2D interpolation (bilinear with log(rho), log(u)) to find c(rho, u)) + // 2D interpolation (bilinear with log(rho), log(u) to find c(rho, u)) + // Density index - idx_rho = + int idx_rho = find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); // Sp. int. energy at this and the next density (in relevant slice of u array) - idx_u_1 = find_value_in_monot_incr_array( + int idx_u_1 = find_value_in_monot_incr_array( log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); - idx_u_2 = find_value_in_monot_incr_array( + int idx_u_2 = find_value_in_monot_incr_array( log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); // If outside the table then extrapolate from the edge and edge-but-one values @@ -645,18 +690,19 @@ INLINE static float SESAME_soundspeed_from_internal_energy( } // Check for duplicates in SESAME tables before interpolation + float intp_rho, intp_u_1, intp_u_2; if (mat->table_log_rho[idx_rho + 1] != mat->table_log_rho[idx_rho]) { intp_rho = (log_rho - mat->table_log_rho[idx_rho]) / (mat->table_log_rho[idx_rho + 1] - mat->table_log_rho[idx_rho]); } else { intp_rho = 1.f; } - if (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] != - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) { - intp_u_1 = - (log_u - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]) / - (mat->table_log_u_rho_T[idx_rho * mat->num_T + (idx_u_1 + 1)] - - mat->table_log_u_rho_T[idx_rho * mat->num_T + idx_u_1]); + const int idx_u_rho_T = idx_rho * mat->num_T + idx_u_1; + if (mat->table_log_u_rho_T[idx_u_rho_T + 1] != + mat->table_log_u_rho_T[idx_u_rho_T]) { + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_u_rho_T]) / + (mat->table_log_u_rho_T[idx_u_rho_T + 1] - + mat->table_log_u_rho_T[idx_u_rho_T]); } else { intp_u_1 = 1.f; } @@ -671,10 +717,10 @@ INLINE static float SESAME_soundspeed_from_internal_energy( } // Table values - c_1 = mat->table_c_rho_T[idx_rho * mat->num_T + idx_u_1]; - c_2 = mat->table_c_rho_T[idx_rho * mat->num_T + idx_u_1 + 1]; - c_3 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; - c_4 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + float c_1 = mat->table_c_rho_T[idx_u_rho_T]; + float c_2 = mat->table_c_rho_T[idx_u_rho_T + 1]; + float c_3 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + float c_4 = mat->table_c_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; // If more than two table values are non-positive then return zero int num_non_pos = 0; @@ -710,22 +756,536 @@ INLINE static float SESAME_soundspeed_from_internal_energy( intp_u_2 = 0; } - c = (1.f - intp_rho) * ((1.f - intp_u_1) * c_1 + intp_u_1 * c_2) + - intp_rho * ((1.f - intp_u_2) * c_3 + intp_u_2 * c_4); + const float c = (1.f - intp_rho) * ((1.f - intp_u_1) * c_1 + intp_u_1 * c_2) + + intp_rho * ((1.f - intp_u_2) * c_3 + intp_u_2 * c_4); // Convert back from log - c = expf(c); - - return c; + return expf(c); } // gas_soundspeed_from_pressure INLINE static float SESAME_soundspeed_from_pressure( - float density, float P, const struct SESAME_params *mat) { + const float density, const float P, const struct SESAME_params *mat) { error("This EOS function is not yet implemented!"); return 0.f; } +// gas_temperature_from_internal_energy +INLINE static float SESAME_temperature_from_internal_energy( + const float density, const float u, const struct SESAME_params *mat) { + + // Return zero if zero internal energy + if (u <= 0.f) { + return 0.f; + } + + const float log_rho = logf(density); + const float log_u = logf(u); + + // 2D interpolation (bilinear with log(rho), log(u) to find T(rho, u) + + // Density index + int idx_rho = + find_value_in_monot_incr_array(log_rho, mat->table_log_rho, mat->num_rho); + + // Sp. int. energy at this and the next density (in relevant slice of u array) + int idx_u_1 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); + int idx_u_2 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho) { + idx_rho = mat->num_rho - 2; + } + if (idx_u_1 <= -1) { + idx_u_1 = 0; + } else if (idx_u_1 >= mat->num_T) { + idx_u_1 = mat->num_T - 2; + } + if (idx_u_2 <= -1) { + idx_u_2 = 0; + } else if (idx_u_2 >= mat->num_T) { + idx_u_2 = mat->num_T - 2; + } + + // Check for duplicates in SESAME tables before interpolation + float intp_u_1, intp_u_2; + const int idx_u_rho_T = idx_rho * mat->num_T + idx_u_1; + if (mat->table_log_u_rho_T[idx_u_rho_T + 1] != + mat->table_log_u_rho_T[idx_u_rho_T]) { + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_u_rho_T]) / + (mat->table_log_u_rho_T[idx_u_rho_T + 1] - + mat->table_log_u_rho_T[idx_u_rho_T]); + } else { + intp_u_1 = 1.f; + } + if (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] != + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) { + intp_u_2 = + (log_u - mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + } else { + intp_u_2 = 1.f; + } + + // Compute line points + float log_rho_1 = mat->table_log_rho[idx_rho]; + float log_rho_2 = mat->table_log_rho[idx_rho + 1]; + float log_T_1 = mat->table_log_T[idx_u_1]; + log_T_1 += + intp_u_1 * (mat->table_log_T[idx_u_1 + 1] - mat->table_log_T[idx_u_1]); + float log_T_2 = mat->table_log_T[idx_u_2]; + log_T_2 += + intp_u_2 * (mat->table_log_T[idx_u_2 + 1] - mat->table_log_T[idx_u_2]); + + // Intersect line passing through (log_rho_1, log_T_1), (log_rho_2, log_T_2) + // with line density = log_rho + + // Check for log_T_1 == log_T_2 + float log_T; + if (log_T_1 == log_T_2) { + log_T = log_T_1; + } else { + // log_rho = slope*log_T + intercept + const float slope = (log_rho_1 - log_rho_2) / (log_T_1 - log_T_2); + const float intercept = log_rho_1 - slope * log_T_1; + log_T = (log_rho - intercept) / slope; + } + + // Convert back from log + return expf(log_T); +} + +// gas_density_from_pressure_and_temperature +INLINE static float SESAME_density_from_pressure_and_temperature( + float P, float T, const struct SESAME_params *mat) { + + // Return zero if pressure is non-positive + if (P <= 0.f) { + return 0.f; + } + + const float log_T = logf(T); + + // 2D interpolation (bilinear with log(T), P to find rho(T, P)) + + // Temperature index + int idx_T = + find_value_in_monot_incr_array(log_T, mat->table_log_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_T <= -1) { + idx_T = 0; + } else if (idx_T >= mat->num_T) { + idx_T = mat->num_T - 2; + } + + // Pressure at this and the next temperature (in relevant vertical slice of P + // array) + int idx_P_1 = vertical_find_value_in_monot_incr_array( + P, mat->table_P_rho_T, mat->num_rho, mat->num_T, idx_T); + int idx_P_2 = vertical_find_value_in_monot_incr_array( + P, mat->table_P_rho_T, mat->num_rho, mat->num_T, idx_T + 1); + + // If outside the table then extrapolate from the edge and edge-but-one values + if (idx_P_1 <= -1) { + idx_P_1 = 0; + } else if (idx_P_1 >= mat->num_rho) { + idx_P_1 = mat->num_rho - 2; + } + if (idx_P_2 <= -1) { + idx_P_2 = 0; + } else if (idx_P_2 >= mat->num_rho) { + idx_P_2 = mat->num_rho - 2; + } + + // Check for duplicates in SESAME tables before interpolation + float intp_P_1, intp_P_2; + if (mat->table_P_rho_T[(idx_P_1 + 1) * mat->num_T + idx_T] != + mat->table_P_rho_T[idx_P_1 * mat->num_T + idx_T]) { + intp_P_1 = (P - mat->table_P_rho_T[idx_P_1 * mat->num_T + idx_T]) / + (mat->table_P_rho_T[(idx_P_1 + 1) * mat->num_T + idx_T] - + mat->table_P_rho_T[idx_P_1 * mat->num_T + idx_T]); + } else { + intp_P_1 = 1.f; + } + if (mat->table_P_rho_T[(idx_P_2 + 1) * mat->num_T + (idx_T + 1)] != + mat->table_P_rho_T[idx_P_2 * mat->num_T + (idx_T + 1)]) { + intp_P_2 = (P - mat->table_P_rho_T[idx_P_2 * mat->num_T + (idx_T + 1)]) / + (mat->table_P_rho_T[(idx_P_2 + 1) * mat->num_T + (idx_T + 1)] - + mat->table_P_rho_T[idx_P_2 * mat->num_T + (idx_T + 1)]); + } else { + intp_P_2 = 1.f; + } + + // Compute line points + const float log_T_1 = mat->table_log_T[idx_T]; + const float log_T_2 = mat->table_log_T[idx_T + 1]; + const float log_rho_1 = (1.f - intp_P_1) * mat->table_log_rho[idx_P_1] + + intp_P_1 * mat->table_log_rho[idx_P_1 + 1]; + const float log_rho_2 = (1.f - intp_P_2) * mat->table_log_rho[idx_P_2] + + intp_P_2 * mat->table_log_rho[idx_P_2 + 1]; + + // Intersect line passing through (log_rho_1, log_T_1), (log_rho_2, log_T_2) + // with line temperature = log_T + + // Check for log_rho_1 == log_rho_2 + float log_rho; + if (log_rho_1 == log_rho_2) { + log_rho = log_rho_1; + } else { + // log_T = slope*log_rho + intercept + const float slope = (log_T_1 - log_T_2) / (log_rho_1 - log_rho_2); + const float intercept = log_T_1 - slope * log_rho_1; + log_rho = (log_T - intercept) / slope; + } + + // Convert back from log + return expf(log_rho); +} + +// gas_density_from_pressure_and_internal_energy +INLINE static float SESAME_density_from_pressure_and_internal_energy( + float P, float u, float rho_ref, float rho_sph, + const struct SESAME_params *mat) { + + // Return the unchanged density if u or P is non-positive + if (u <= 0.f || P <= 0.f) { + return rho_sph; + } + + // Convert inputs to log + const float log_u = logf(u); + const float log_P = logf(P); + const float log_rho_ref = logf(rho_ref); + + // Find rounded down index of reference density. This is where we start our + // search + int idx_rho_ref = find_value_in_monot_incr_array( + log_rho_ref, mat->table_log_rho, mat->num_rho); + + // If no roots are found in the current search range, we increase search range + // by search_factor_log_rho above and below the reference density each + // iteration. + const float search_factor_log_rho = logf(10.f); + + // Initialise the minimum and maximum densities we're searching to at the + // reference density. These will change before the first iteration. + float log_rho_min = log_rho_ref; + float log_rho_max = log_rho_ref; + + // Initialise search indices around rho_ref + int idx_rho_below_min, idx_rho_above_max; + + // If we find a root, it will get stored as closest_root + float closest_root = -1.f; + float root_below; + + // Initialise pressures + float P_above_lower, P_above_upper; + float P_below_lower, P_below_upper; + P_above_upper = 0.f; + P_below_lower = 0.f; + + // Increase search range by search_factor_log_rho + log_rho_max += search_factor_log_rho; + idx_rho_above_max = find_value_in_monot_incr_array( + log_rho_max, mat->table_log_rho, mat->num_rho); + log_rho_min -= search_factor_log_rho; + idx_rho_below_min = find_value_in_monot_incr_array( + log_rho_min, mat->table_log_rho, mat->num_rho); + + // When searching above/below, we are looking for where the pressure P(rho, u) + // of the table densities changes from being less than to more than, or vice + // versa, the desired pressure. If this is the case, there is a root between + // these table values of rho. + + // First look for roots above rho_ref + int idx_u_rho_T; + float intp_rho; + for (int idx_rho = idx_rho_ref; idx_rho <= idx_rho_above_max; idx_rho++) { + + // This is similar to P_u_rho, but we're not interested in intp_rho, + // and instead calculate the pressure for both intp_rho=0 and intp_rho=1 + + // Sp. int. energy at this and the next density (in relevant slice of u + // array) + int idx_u_1 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); + int idx_u_2 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one + // values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho) { + idx_rho = mat->num_rho - 2; + } + if (idx_u_1 <= -1) { + idx_u_1 = 0; + } else if (idx_u_1 >= mat->num_T) { + idx_u_1 = mat->num_T - 2; + } + if (idx_u_2 <= -1) { + idx_u_2 = 0; + } else if (idx_u_2 >= mat->num_T) { + idx_u_2 = mat->num_T - 2; + } + + float intp_u_1, intp_u_2; + idx_u_rho_T = idx_rho * mat->num_T + idx_u_1; + if (mat->table_log_u_rho_T[idx_u_rho_T + 1] != + mat->table_log_u_rho_T[idx_u_rho_T]) { + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_u_rho_T]) / + (mat->table_log_u_rho_T[idx_u_rho_T + 1] - + mat->table_log_u_rho_T[idx_u_rho_T]); + } else { + intp_u_1 = 1.f; + } + if (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] != + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) { + intp_u_2 = + (log_u - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + } else { + intp_u_2 = 1.f; + } + + // Table values + float P_1 = mat->table_P_rho_T[idx_u_rho_T]; + float P_2 = mat->table_P_rho_T[idx_u_rho_T + 1]; + float P_3 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + float P_4 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + + // If below the minimum u at this rho then just use the lowest table values + if ((idx_rho > 0.f) && + ((intp_u_1 < 0.f) || (intp_u_2 < 0.f) || (P_1 > P_2) || (P_3 > P_4))) { + intp_u_1 = 0; + intp_u_2 = 0; + } + + // If more than two table values are non-positive then return zero + int num_non_pos = 0; + if (P_1 <= 0.f) num_non_pos++; + if (P_2 <= 0.f) num_non_pos++; + if (P_3 <= 0.f) num_non_pos++; + if (P_4 <= 0.f) num_non_pos++; + if (num_non_pos > 0) { + // If just one or two are non-positive then replace them with a tiny value + // Unless already trying to extrapolate in which case return zero + if ((num_non_pos > 2) || (mat->P_tiny == 0.f) || (intp_u_1 < 0.f) || + (intp_u_2 < 0.f)) { + break; // return rho_sph; + } + if (P_1 <= 0.f) P_1 = mat->P_tiny; + if (P_2 <= 0.f) P_2 = mat->P_tiny; + if (P_3 <= 0.f) P_3 = mat->P_tiny; + if (P_4 <= 0.f) P_4 = mat->P_tiny; + } + + // Interpolate with the log values + P_1 = logf(P_1); + P_2 = logf(P_2); + P_3 = logf(P_3); + P_4 = logf(P_4); + float P_1_2 = (1.f - intp_u_1) * P_1 + intp_u_1 * P_2; + float P_3_4 = (1.f - intp_u_2) * P_3 + intp_u_2 * P_4; + + // Pressure for intp_rho = 0 + P_above_lower = expf(P_1_2); + + // Because of linear interpolation, pressures are not exactly continuous + // as we go from one side of a grid point to another. See if there is + // a root between the last P_above_upper and the new P_above_lower, + // which are approx the same. + if (idx_rho != idx_rho_ref) { + if ((P_above_lower - P) * (P_above_upper - P) <= 0) { + closest_root = expf(mat->table_log_rho[idx_rho]); + break; + } + } + + // Pressure for intp_rho = 1 + P_above_upper = expf(P_3_4); + + // Does the pressure of the adjacent table densities switch from being + // above to below the desired pressure, or vice versa? If so, there is a + // root. + if ((P_above_lower - P) * (P_above_upper - P) <= 0.f) { + + // If there is a root, interpolate between the table values: + intp_rho = (log_P - P_1_2) / (P_3_4 - P_1_2); + + closest_root = expf(mat->table_log_rho[idx_rho] + + intp_rho * (mat->table_log_rho[idx_rho + 1] - + mat->table_log_rho[idx_rho])); + + // If the root is between the same table values as the reference value, + // then this is the closest root, so we can return it without further + // searching + if (idx_rho == idx_rho_ref) { + return closest_root; + } + + // Found a root, so no need to search higher densities + break; + } + } + + // If we found a root above, change search range below so that we're only + // looking for closer (in log) roots than the one we found + if (closest_root > 0.f) { + log_rho_min = log_rho_ref - (logf(closest_root) - log_rho_ref); + idx_rho_below_min = find_value_in_monot_incr_array( + log_rho_min, mat->table_log_rho, mat->num_rho); + } + + // Now look for roots below rho_ref + for (int idx_rho = idx_rho_ref; idx_rho >= idx_rho_below_min; idx_rho--) { + + // Sp. int. energy at this and the next density (in relevant slice of u + // array) + int idx_u_1 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + idx_rho * mat->num_T, mat->num_T); + int idx_u_2 = find_value_in_monot_incr_array( + log_u, mat->table_log_u_rho_T + (idx_rho + 1) * mat->num_T, mat->num_T); + + // If outside the table then extrapolate from the edge and edge-but-one + // values + if (idx_rho <= -1) { + idx_rho = 0; + } else if (idx_rho >= mat->num_rho) { + idx_rho = mat->num_rho - 2; + } + if (idx_u_1 <= -1) { + idx_u_1 = 0; + } else if (idx_u_1 >= mat->num_T) { + idx_u_1 = mat->num_T - 2; + } + if (idx_u_2 <= -1) { + idx_u_2 = 0; + } else if (idx_u_2 >= mat->num_T) { + idx_u_2 = mat->num_T - 2; + } + + idx_u_rho_T = idx_rho * mat->num_T + idx_u_1; + float intp_u_1, intp_u_2; + if (mat->table_log_u_rho_T[idx_u_rho_T + 1] != + mat->table_log_u_rho_T[idx_u_rho_T]) { + intp_u_1 = (log_u - mat->table_log_u_rho_T[idx_u_rho_T]) / + (mat->table_log_u_rho_T[idx_u_rho_T + 1] - + mat->table_log_u_rho_T[idx_u_rho_T]); + } else { + intp_u_1 = 1.f; + } + if (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] != + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) { + intp_u_2 = + (log_u - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]) / + (mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + (idx_u_2 + 1)] - + mat->table_log_u_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]); + } else { + intp_u_2 = 1.f; + } + + // Table values + float P_1 = mat->table_P_rho_T[idx_u_rho_T]; + float P_2 = mat->table_P_rho_T[idx_u_rho_T + 1]; + float P_3 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2]; + float P_4 = mat->table_P_rho_T[(idx_rho + 1) * mat->num_T + idx_u_2 + 1]; + + // If below the minimum u at this rho then just use the lowest table values + if ((idx_rho > 0.f) && + ((intp_u_1 < 0.f) || (intp_u_2 < 0.f) || (P_1 > P_2) || (P_3 > P_4))) { + intp_u_1 = 0; + intp_u_2 = 0; + } + + // If more than two table values are non-positive then return zero + int num_non_pos = 0; + if (P_1 <= 0.f) num_non_pos++; + if (P_2 <= 0.f) num_non_pos++; + if (P_3 <= 0.f) num_non_pos++; + if (P_4 <= 0.f) num_non_pos++; + if (num_non_pos > 0) { + // If just one or two are non-positive then replace them with a tiny value + // Unless already trying to extrapolate in which case return zero + if ((num_non_pos > 2) || (mat->P_tiny == 0.f) || (intp_u_1 < 0.f) || + (intp_u_2 < 0.f)) { + break; + } + if (P_1 <= 0.f) P_1 = mat->P_tiny; + if (P_2 <= 0.f) P_2 = mat->P_tiny; + if (P_3 <= 0.f) P_3 = mat->P_tiny; + if (P_4 <= 0.f) P_4 = mat->P_tiny; + } + + // Interpolate with the log values + P_1 = logf(P_1); + P_2 = logf(P_2); + P_3 = logf(P_3); + P_4 = logf(P_4); + const float P_1_2 = (1.f - intp_u_1) * P_1 + intp_u_1 * P_2; + const float P_3_4 = (1.f - intp_u_2) * P_3 + intp_u_2 * P_4; + + // Pressure for intp_rho = 1 + P_below_upper = expf(P_3_4); + // Because of linear interpolation, pressures are not exactly continuous + // as we go from one side of a grid point to another. See if there is + // a root between the last P_below_lower and the new P_below_upper, + // which are approx the same. + if (idx_rho != idx_rho_ref) { + if ((P_below_lower - P) * (P_below_upper - P) <= 0) { + closest_root = expf(mat->table_log_rho[idx_rho + 1]); + break; + } + } + // Pressure for intp_rho = 0 + P_below_lower = expf(P_1_2); + + // Does the pressure of the adjacent table densities switch from being + // above to below the desired pressure, or vice versa? If so, there is a + // root. + if ((P_below_lower - P) * (P_below_upper - P) <= 0.f) { + + // If there is a root, interpolate between the table values: + intp_rho = (log_P - P_1_2) / (P_3_4 - P_1_2); + + root_below = expf(mat->table_log_rho[idx_rho] + + intp_rho * (mat->table_log_rho[idx_rho + 1] - + mat->table_log_rho[idx_rho])); + + // If we found a root above, which one is closer to the reference rho? + if (closest_root > 0.f) { + if (fabsf(logf(root_below) - logf(rho_ref)) < + fabsf(logf(closest_root) - logf(rho_ref))) { + closest_root = root_below; + } + } else { + closest_root = root_below; + } + // Found a root, so no need to search higher densities + break; + } + } + + // Return the root if we found one + if (closest_root > 0.f) { + return closest_root; + } + + // If we don't find a root before we reach max_counter, return rho_ref. Maybe + // we should give an error here? + return rho_sph; +} #endif /* SWIFT_SESAME_EQUATION_OF_STATE_H */ diff --git a/src/equation_of_state/planetary/tillotson.h b/src/equation_of_state/planetary/tillotson.h index 5831b1785485d5dc2563718c94fc9cc04a08b822..dc5b5576c33616446795451fd0229e6e58fdfec4 100644 --- a/src/equation_of_state/planetary/tillotson.h +++ b/src/equation_of_state/planetary/tillotson.h @@ -37,12 +37,16 @@ #include "equation_of_state.h" #include "inline.h" #include "physical_constants.h" +#include "sesame.h" #include "units.h" // Tillotson parameters struct Til_params { - float rho_0, a, b, A, B, u_0, u_iv, u_cv, alpha, beta, eta_min, eta_zero, - P_min; + float rho_0, a, b, A, B, u_0, u_iv, u_cv, alpha, beta; + float eta_min, eta_zero, P_min, C_V; + float *A1_u_cold; + float rho_cold_min, rho_cold_max; + float rho_min, rho_max; enum eos_planetary_material_id mat_id; }; @@ -62,7 +66,12 @@ INLINE static void set_Til_iron(struct Til_params *mat, mat->beta = 5.0f; mat->eta_min = 0.0f; mat->eta_zero = 0.0f; - mat->P_min = 0.0f; + mat->P_min = 0.01f; + mat->C_V = 449.0f; + mat->rho_cold_min = 100.0f; + mat->rho_cold_max = 1.0e5f; + mat->rho_min = 1.0f; + mat->rho_max = 1.0e5f; } INLINE static void set_Til_granite(struct Til_params *mat, enum eos_planetary_material_id mat_id) { @@ -79,7 +88,12 @@ INLINE static void set_Til_granite(struct Til_params *mat, mat->beta = 5.0f; mat->eta_min = 0.0f; mat->eta_zero = 0.0f; - mat->P_min = 0.0f; + mat->P_min = 0.01f; + mat->C_V = 790.0f; + mat->rho_cold_min = 100.0f; + mat->rho_cold_max = 1.0e5f; + mat->rho_min = 1.0f; + mat->rho_max = 1.0e5f; } INLINE static void set_Til_basalt(struct Til_params *mat, enum eos_planetary_material_id mat_id) { @@ -96,7 +110,12 @@ INLINE static void set_Til_basalt(struct Til_params *mat, mat->beta = 5.0f; mat->eta_min = 0.0f; mat->eta_zero = 0.0f; - mat->P_min = 0.0f; + mat->P_min = 0.01f; + mat->C_V = 790.0f; + mat->rho_cold_min = 100.0f; + mat->rho_cold_max = 1.0e5f; + mat->rho_min = 1.0f; + mat->rho_max = 1.0e5f; } INLINE static void set_Til_water(struct Til_params *mat, enum eos_planetary_material_id mat_id) { @@ -113,7 +132,77 @@ INLINE static void set_Til_water(struct Til_params *mat, mat->beta = 5.0f; mat->eta_min = 0.925f; mat->eta_zero = 0.875f; + mat->P_min = 0.01f; + mat->C_V = 4186.0f; + mat->rho_cold_min = 100.0f; + mat->rho_cold_max = 1.0e5f; + mat->rho_min = 1.0f; + mat->rho_max = 1.0e5f; +} +INLINE static void set_Til_ice(struct Til_params *mat, + enum eos_planetary_material_id mat_id) { + mat->mat_id = mat_id; + mat->rho_0 = 1293.0f; + mat->a = 0.3f; + mat->b = 0.1f; + mat->A = 1.07e10f; + mat->B = 6.5e10f; + mat->u_0 = 1.0e7f; + mat->u_iv = 7.73e5f; + mat->u_cv = 3.04e6f; + mat->alpha = 10.0f; + mat->beta = 5.0f; + mat->eta_min = 0.925f; + mat->eta_zero = 0.875f; mat->P_min = 0.0f; + mat->C_V = 2093.0f; + mat->rho_cold_min = 100.0f; + mat->rho_cold_max = 1.0e5f; + mat->rho_min = 1.0f; + mat->rho_max = 1.0e5f; +} + +/* + Read the parameters from a file. + + File contents + ------------- + # header (5 lines) + rho_0 (kg/m3) a (-) b (-) A (Pa) B (Pa) + u_0 (J) u_iv (J) u_cv (J) alpha (-) beta (-) + eta_min (-) eta_zero (-) P_min (Pa) C_V (J kg^-1 K^-1) + rho_cold_min (kg/m3) rho_cold_max (kg/m3) rho_min (kg/m3) rho_max (kg/m3) +*/ +INLINE static void set_Til_custom(struct Til_params *mat, + enum eos_planetary_material_id mat_id, + char *param_file) { + mat->mat_id = mat_id; + + // Load table contents from file + FILE *f = fopen(param_file, "r"); + if (f == NULL) + error("Failed to open the Tillotson EoS file '%s'", param_file); + + // Skip header lines + skip_lines(f, 5); + + // Read parameters (SI) + int c; + c = fscanf(f, "%f %f %f %f %f", &mat->rho_0, &mat->a, &mat->b, &mat->A, + &mat->B); + if (c != 5) error("Failed to read the Tillotson EoS file %s", param_file); + + c = fscanf(f, "%f %f %f %f %f", &mat->u_0, &mat->u_iv, &mat->u_cv, + &mat->alpha, &mat->beta); + if (c != 5) error("Failed to read the Tillotson EoS file %s", param_file); + + c = fscanf(f, "%f %f %f %f", &mat->eta_min, &mat->eta_zero, &mat->P_min, + &mat->C_V); + if (c != 4) error("Failed to read the Tillotson EoS file %s", param_file); + + c = fscanf(f, "%f %f %f %f", &mat->rho_cold_min, &mat->rho_cold_max, + &mat->rho_min, &mat->rho_max); + if (c != 4) error("Failed to read the Tillotson EoS file %s", param_file); } // Convert to internal units @@ -123,6 +212,8 @@ INLINE static void convert_units_Til(struct Til_params *mat, struct unit_system si; units_init_si(&si); + const int N = 10000; + // SI to cgs mat->rho_0 *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); mat->A *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE); @@ -132,6 +223,19 @@ INLINE static void convert_units_Til(struct Til_params *mat, mat->u_cv *= units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); mat->P_min *= units_cgs_conversion_factor(&si, UNIT_CONV_PRESSURE); + for (int i = 0; i < N; i++) { + mat->A1_u_cold[i] *= + units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); + } + + mat->C_V *= units_cgs_conversion_factor(&si, UNIT_CONV_ENERGY_PER_UNIT_MASS); + // Entropy units don't work? using internal kelvin + + mat->rho_cold_min *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); + mat->rho_cold_max *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); + mat->rho_min *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); + mat->rho_max *= units_cgs_conversion_factor(&si, UNIT_CONV_DENSITY); + // cgs to internal mat->rho_0 /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); mat->A /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); @@ -140,11 +244,24 @@ INLINE static void convert_units_Til(struct Til_params *mat, mat->u_iv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); mat->u_cv /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); mat->P_min /= units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE); + + for (int i = 0; i < N; i++) { + mat->A1_u_cold[i] /= + units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + } + + mat->C_V /= units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + // Entropy units don't work? using internal kelvin + + mat->rho_cold_min /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + mat->rho_cold_max /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + mat->rho_min /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + mat->rho_max /= units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); } // gas_internal_energy_from_entropy INLINE static float Til_internal_energy_from_entropy( - float density, float entropy, const struct Til_params *mat) { + const float density, const float entropy, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -152,7 +269,8 @@ INLINE static float Til_internal_energy_from_entropy( } // gas_pressure_from_entropy -INLINE static float Til_pressure_from_entropy(float density, float entropy, +INLINE static float Til_pressure_from_entropy(const float density, + const float entropy, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -161,7 +279,8 @@ INLINE static float Til_pressure_from_entropy(float density, float entropy, } // gas_entropy_from_pressure -INLINE static float Til_entropy_from_pressure(float density, float pressure, +INLINE static float Til_entropy_from_pressure(const float density, + const float pressure, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -170,7 +289,8 @@ INLINE static float Til_entropy_from_pressure(float density, float pressure, } // gas_soundspeed_from_entropy -INLINE static float Til_soundspeed_from_entropy(float density, float entropy, +INLINE static float Til_soundspeed_from_entropy(const float density, + const float entropy, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -180,14 +300,14 @@ INLINE static float Til_soundspeed_from_entropy(float density, float entropy, // gas_entropy_from_internal_energy INLINE static float Til_entropy_from_internal_energy( - float density, float u, const struct Til_params *mat) { + const float density, const float u, const struct Til_params *mat) { return 0.f; } // gas_pressure_from_internal_energy INLINE static float Til_pressure_from_internal_energy( - float density, float u, const struct Til_params *mat) { + const float density, const float u, const struct Til_params *mat) { const float eta = density / mat->rho_0; const float eta_sq = eta * eta; @@ -195,10 +315,9 @@ INLINE static float Til_pressure_from_internal_energy( const float nu = 1.f / eta - 1.f; const float w = u / (mat->u_0 * eta_sq) + 1.f; const float w_inv = 1.f / w; - float P_c, P_e, P; // Condensed or cold - P_c = + float P_c = (mat->a + mat->b * w_inv) * density * u + mat->A * mu + mat->B * mu * mu; if (eta < mat->eta_zero) { P_c = 0.f; @@ -206,11 +325,12 @@ INLINE static float Til_pressure_from_internal_energy( P_c *= (eta - mat->eta_zero) / (mat->eta_min - mat->eta_zero); } // Expanded and hot - P_e = mat->a * density * u + - (mat->b * density * u * w_inv + mat->A * mu * expf(-mat->beta * nu)) * - expf(-mat->alpha * nu * nu); + float P_e = mat->a * density * u + (mat->b * density * u * w_inv + + mat->A * mu * expf(-mat->beta * nu)) * + expf(-mat->alpha * nu * nu); // Condensed or cold state + float P; if ((1.f < eta) || (u < mat->u_iv)) { P = P_c; } @@ -234,7 +354,7 @@ INLINE static float Til_pressure_from_internal_energy( // gas_internal_energy_from_pressure INLINE static float Til_internal_energy_from_pressure( - float density, float P, const struct Til_params *mat) { + const float density, const float P, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -243,7 +363,7 @@ INLINE static float Til_internal_energy_from_pressure( // gas_soundspeed_from_internal_energy INLINE static float Til_soundspeed_from_internal_energy( - float density, float u, const struct Til_params *mat) { + const float density, const float u, const struct Til_params *mat) { const float rho_0_inv = 1.f / mat->rho_0; const float eta = density * rho_0_inv; @@ -256,25 +376,25 @@ INLINE static float Til_soundspeed_from_internal_energy( const float w_inv_sq = w_inv * w_inv; const float exp_beta = expf(-mat->beta * nu); const float exp_alpha = expf(-mat->alpha * nu * nu); - float P_c, P_e, c_sq_c, c_sq_e, c_sq; // Condensed or cold - P_c = + float P_c = (mat->a + mat->b * w_inv) * density * u + mat->A * mu + mat->B * mu * mu; if (eta < mat->eta_zero) { P_c = 0.f; } else if (eta < mat->eta_min) { P_c *= (eta - mat->eta_zero) / (mat->eta_min - mat->eta_zero); } - c_sq_c = P_c * rho_inv * (1.f + mat->a + mat->b * w_inv) + - mat->b * (w - 1.f) * w_inv_sq * (2.f * u - P_c * rho_inv) + - rho_inv * (mat->A + mat->B * (eta_sq - 1.f)); + float c_sq_c = P_c * rho_inv * (1.f + mat->a + mat->b * w_inv) + + mat->b * (w - 1.f) * w_inv_sq * (2.f * u - P_c * rho_inv) + + rho_inv * (mat->A + mat->B * (eta_sq - 1.f)); // Expanded and hot - P_e = mat->a * density * u + - (mat->b * density * u * w_inv + mat->A * mu * exp_beta) * exp_alpha; + float P_e = + mat->a * density * u + + (mat->b * density * u * w_inv + mat->A * mu * exp_beta) * exp_alpha; - c_sq_e = + float c_sq_e = P_e * rho_inv * (1.f + mat->a + mat->b * w_inv * exp_alpha) + (mat->b * density * u * w_inv_sq / eta_sq * (rho_inv / mat->u_0 * (2.f * u - P_e * rho_inv) + @@ -285,6 +405,7 @@ INLINE static float Til_soundspeed_from_internal_energy( exp_alpha; // Condensed or cold state + float c_sq; if ((1.f < eta) || (u < mat->u_iv)) { c_sq = c_sq_c; } @@ -304,7 +425,8 @@ INLINE static float Til_soundspeed_from_internal_energy( } // gas_soundspeed_from_pressure -INLINE static float Til_soundspeed_from_pressure(float density, float P, +INLINE static float Til_soundspeed_from_pressure(const float density, + const float P, const struct Til_params *mat) { error("This EOS function is not yet implemented!"); @@ -312,4 +434,494 @@ INLINE static float Til_soundspeed_from_pressure(float density, float P, return 0.f; } +// Compute u cold +INLINE static float compute_u_cold( + const float density, const struct Til_params *mat, + const enum eos_planetary_material_id mat_id) { + const int N = 10000; + const float rho_0 = mat->rho_0; + const float drho = (density - rho_0) / N; + + float x = rho_0; + float u_cold = 1e-9; + for (int i = 0; i < N; i++) { + x += drho; + u_cold += + Til_pressure_from_internal_energy(x, u_cold, mat) * drho / (x * x); + } + + return u_cold; +} + +// Compute A1_u_cold +INLINE static void set_Til_u_cold(struct Til_params *mat, + enum eos_planetary_material_id mat_id) { + + const int N = 10000; + const float rho_min = 100.f; + const float rho_max = 100000.f; + + // Allocate table memory + mat->A1_u_cold = (float *)malloc(N * sizeof(float)); + + float rho = rho_min; + const float drho = (rho_max - rho_min) / (N - 1); + + for (int i = 0; i < N; i++) { + mat->A1_u_cold[i] = compute_u_cold(rho, mat, mat_id); + rho += drho; + } +} + +// Compute u cold fast from precomputed values +INLINE static float compute_fast_u_cold(const float density, + const struct Til_params *mat) { + + const int N = 10000; + const float rho_min = mat->rho_cold_min; + const float rho_max = mat->rho_cold_max; + + const float drho = (rho_max - rho_min) / (N - 1); + + const int a = (int)((density - rho_min) / drho); + const int b = a + 1; + + float u_cold; + if (a >= 0 && a < (N - 1)) { + u_cold = mat->A1_u_cold[a]; + u_cold += ((mat->A1_u_cold[b] - mat->A1_u_cold[a]) / drho) * + (density - rho_min - a * drho); + } else if (density < rho_min) { + u_cold = mat->A1_u_cold[0]; + } else { + u_cold = mat->A1_u_cold[N - 1]; + u_cold += ((mat->A1_u_cold[N - 1] - mat->A1_u_cold[N - 2]) / drho) * + (density - rho_max); + } + return u_cold; +} + +// gas_temperature_from_internal_energy +INLINE static float Til_temperature_from_internal_energy( + const float density, const float u, const struct Til_params *mat) { + + const float u_cold = compute_fast_u_cold(density, mat); + + float T = (u - u_cold) / (mat->C_V); + if (T < 0.f) { + T = 0.f; + } + + return T; +} + +// gas_pressure_from_density_and_temperature +INLINE static float Til_pressure_from_temperature( + const float density, const float T, const struct Til_params *mat) { + + const float u = compute_fast_u_cold(density, mat) + mat->C_V * T; + const float P = Til_pressure_from_internal_energy(density, u, mat); + + return P; +} + +// gas_density_from_pressure_and_temperature +INLINE static float Til_density_from_pressure_and_temperature( + const float P, const float T, const struct Til_params *mat) { + + float rho_min = mat->rho_min; + float rho_max = mat->rho_max; + float rho_mid = (rho_min + rho_max) / 2.f; + + // Check for P == 0 or T == 0 + float P_des; + if (P <= mat->P_min) { + P_des = mat->P_min; + } else { + P_des = P; + } + + float P_min = Til_pressure_from_temperature(rho_min, T, mat); + float P_mid = Til_pressure_from_temperature(rho_mid, T, mat); + float P_max = Til_pressure_from_temperature(rho_max, T, mat); + + // quick fix? + if (P_des < P_min) { + P_des = P_min; + } + + const float tolerance = 0.001 * rho_min; + int counter = 0; + const int max_counter = 200; + if (P_des >= P_min && P_des <= P_max) { + while ((rho_max - rho_min) > tolerance && counter < max_counter) { + + P_min = Til_pressure_from_temperature(rho_min, T, mat); + P_mid = Til_pressure_from_temperature(rho_mid, T, mat); + P_max = Til_pressure_from_temperature(rho_max, T, mat); + + const float f0 = P_des - P_min; + const float f2 = P_des - P_mid; + + if ((f0 * f2) > 0) { + rho_min = rho_mid; + } else { + rho_max = rho_mid; + } + + rho_mid = (rho_min + rho_max) / 2.f; + counter += 1; + } + } else { + error("Error in Til_density_from_pressure_and_temperature"); + return 0.f; + } + return rho_mid; +} + +// gas_density_from_pressure_and_internal_energy +INLINE static float Til_density_from_pressure_and_internal_energy( + const float P, const float u, const float rho_ref, const float rho_sph, + const struct Til_params *mat) { + + if (P <= mat->P_min || u == 0) { + return rho_sph; + } + + // We start search on the same curve as rho_ref, since this is most likely + // curve to find rho on + float eta_ref = rho_ref / mat->rho_0; + + /* + There are 5 possible curves: + 1: cold_min + 2: cold + 3: hybrid_min + 4: hybrid + 5: hot + + These curves cover different eta ranges within three different regions of u: + u REGION 1 (u < u_iv): + eta < eta_min: cold_min + eta_min < eta: cold + + u REGION 2 (u_iv < u < u_cv): + eta < eta_min: hybrid_min + eta_min < eta < 1: hybrid + 1 < eta: cold + + u REGION 3 (u_cv < u): + eta < 1: hot + 1 < eta: cold + + NOTE: for a lot of EoS, eta_min = 0, so search this region last if given the + option to save time for most EoS + */ + enum Til_region { + Til_region_none, + Til_region_cold_min, + Til_region_cold, + Til_region_hybrid_min, + Til_region_hybrid, + Til_region_hot + }; + + // Based on our u region, what possible curves can rho be on? Ordered based on + // order we search for roots. Numbers correspond to curves in order given + // above. 0 is a dummy which breaks the loop. + enum Til_region possible_curves[3]; + // u REGION 1 + if (u <= mat->u_iv) { + if (eta_ref <= mat->eta_min) { + possible_curves[0] = Til_region_cold_min; + possible_curves[1] = Til_region_cold; + possible_curves[2] = Til_region_none; + } else { + possible_curves[0] = Til_region_cold; + possible_curves[1] = Til_region_cold_min; + possible_curves[2] = Til_region_none; + } + // u REGION 2 + } else if (u <= mat->u_cv) { + if (eta_ref <= mat->eta_min) { + possible_curves[0] = Til_region_hybrid_min; + possible_curves[1] = Til_region_hybrid; + possible_curves[2] = Til_region_cold; + } else if (eta_ref <= 1) { + possible_curves[0] = Til_region_hybrid; + possible_curves[1] = Til_region_cold; + possible_curves[2] = Til_region_hybrid_min; + } else { + possible_curves[0] = Til_region_cold; + possible_curves[1] = Til_region_hybrid; + possible_curves[2] = Til_region_hybrid_min; + } + // u REGION 3 + } else { + if (eta_ref <= 1) { + possible_curves[0] = Til_region_hot; + possible_curves[1] = Til_region_cold; + possible_curves[2] = Til_region_none; + } else { + possible_curves[0] = Til_region_cold; + possible_curves[1] = Til_region_hot; + possible_curves[2] = Til_region_none; + } + } + // Newton-Raphson + const int max_iter = 10; + const float tol = 1e-5; + + // loops over possible curves + for (int i = 0; i < 3; i++) { + + enum Til_region curve = possible_curves[i]; + + // if there are only two possible curves, break when we get to three and + // haven't found a root + if (curve == Til_region_none) { + break; + } + + // Start iteration at reference value + float rho_iter = rho_ref; + + // Constrain our initial guess to be on the curve we're currently looking at + // in the first loop, this is already satisfied. + if (i > 0) { + + // u REGION 1 + if (u <= mat->u_iv) { + if (curve == Til_region_cold_min) { + if (rho_iter > mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + // u REGION 2 + } else if (u <= mat->u_cv) { + if (curve == Til_region_hybrid_min) { + if (rho_iter > mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else if (curve == Til_region_hybrid) { + if (rho_iter < mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + if (rho_iter > mat->rho_0) { + rho_iter = mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->rho_0) { + rho_iter = mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + + // u REGION 3 + } else { + if (curve == Til_region_hot) { + if (rho_iter > mat->rho_0) { + rho_iter = mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->rho_0) { + rho_iter = mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + } + } + + // Set this to an arbitrary number so we definitely dont't think we converge + // straigt away + float last_rho_iter = -1e5; + + // Now iterate + for (int j = 0; j < max_iter; j++) { + + const float eta_iter = rho_iter / mat->rho_0; + const float eta_iter_sq = eta_iter * eta_iter; + const float mu_iter = eta_iter - 1.0f; + const float nu_iter = 1.0f / eta_iter - 1.0f; + const float w_iter = u / (mat->u_0 * eta_iter_sq) + 1.0f; + const float w_iter_inv = 1.0f / w_iter; + const float exp1 = expf(-mat->beta * nu_iter); + const float exp2 = expf(-mat->alpha * nu_iter * nu_iter); + + // Derivatives + const float dw_inv_drho_iter = + (2.f * mat->u_0 * u * eta_iter / mat->rho_0) / + ((u + mat->u_0 * eta_iter_sq) * (u + mat->u_0 * eta_iter_sq)); + const float dmu_drho_iter = 1.f / mat->rho_0; + const float dmu_sq_drho_iter = + 2.f * rho_iter / (mat->rho_0 * mat->rho_0) - 2.f / mat->rho_0; + const float dexp1_drho_iter = + mat->beta * mat->rho_0 * exp1 / (rho_iter * rho_iter); + const float dexp2_drho_iter = 2.f * mat->alpha * mat->rho_0 * + (mat->rho_0 - rho_iter) * exp2 / + (rho_iter * rho_iter * rho_iter); + + // Use P_fraction to determine whether we've converged on a root + float P_fraction; + + // Newton-Raphson + float P_c_iter, dP_c_drho_iter, P_h_iter, dP_h_drho_iter; + + // if "cold" or "hybrid" + if (curve == Til_region_cold || curve == Til_region_hybrid) { + P_c_iter = (mat->a + mat->b * w_iter_inv) * rho_iter * u + + mat->A * mu_iter + mat->B * mu_iter * mu_iter - P; + dP_c_drho_iter = (mat->a + mat->b * w_iter_inv) * u + + mat->b * u * rho_iter * dw_inv_drho_iter + + mat->A * dmu_drho_iter + mat->B * dmu_sq_drho_iter; + P_fraction = P_c_iter / P; + + // if curve is cold then we've got everything we need + if (curve == Til_region_cold) { + rho_iter -= P_c_iter / dP_c_drho_iter; + // Don't use these: + P_h_iter = 0.f; + dP_h_drho_iter = 0.f; + } + // if "cold_min" or "hybrid_min" + // Can only have one version of the cold curve, therefore either use the + // min version or the normal version hence "else if" + } else if (curve == Til_region_cold_min || + curve == Til_region_hybrid_min) { + P_c_iter = ((mat->a + mat->b * w_iter_inv) * rho_iter * u + + mat->A * mu_iter + mat->B * mu_iter * mu_iter) * + (eta_iter - mat->eta_zero) / + (mat->eta_min - mat->eta_zero) - + P; + dP_c_drho_iter = + ((mat->a + mat->b * w_iter_inv) * u + + mat->b * u * rho_iter * dw_inv_drho_iter + mat->A * dmu_drho_iter + + mat->B * dmu_sq_drho_iter) * + (eta_iter - mat->eta_zero) / (mat->eta_min - mat->eta_zero) + + ((mat->a + mat->b * w_iter_inv) * rho_iter * u + mat->A * mu_iter + + mat->B * mu_iter * mu_iter) * + (1 / (mat->rho_0 * (mat->eta_min - mat->eta_zero))); + P_fraction = P_c_iter / P; + + // if curve is cold_min then we've got everything we need + if (curve == Til_region_cold_min) { + rho_iter -= P_c_iter / dP_c_drho_iter; + // Don't use these: + P_c_iter = 0.f; + dP_c_drho_iter = 0.f; + } + } + + // if "hybrid_min" or "hybrid" or "hot" + if (curve == Til_region_hybrid_min || curve == Til_region_hybrid || + curve == Til_region_hot) { + P_h_iter = + mat->a * rho_iter * u + + (mat->b * rho_iter * u * w_iter_inv + mat->A * mu_iter * exp1) * + exp2 - + P; + dP_h_drho_iter = + mat->a * u + + (mat->b * u * w_iter_inv + + mat->b * u * rho_iter * dw_inv_drho_iter + + mat->A * mu_iter * dexp1_drho_iter + + mat->A * exp1 * dmu_drho_iter) * + exp2 + + (mat->b * rho_iter * u * w_iter_inv + mat->A * mu_iter * exp1) * + dexp2_drho_iter; + P_fraction = P_h_iter / P; + + // if curve is hot then we've got everything we need + if (curve == Til_region_hot) { + rho_iter -= P_h_iter / dP_h_drho_iter; + } + } + + // If we are on a hybrid or hybrid_min curve, we combie hot and cold + // curves + if (curve == Til_region_hybrid_min || curve == Til_region_hybrid) { + const float P_hybrid_iter = + ((u - mat->u_iv) * P_h_iter + (mat->u_cv - u) * P_c_iter) / + (mat->u_cv - mat->u_iv); + const float dP_hybrid_drho_iter = ((u - mat->u_iv) * dP_h_drho_iter + + (mat->u_cv - u) * dP_c_drho_iter) / + (mat->u_cv - mat->u_iv); + rho_iter -= P_hybrid_iter / dP_hybrid_drho_iter; + P_fraction = P_hybrid_iter / P; + } + + // Now we have to constrain the new rho_iter to the curve we're on + // u REGION 1 + if (u <= mat->u_iv) { + if (curve == Til_region_cold_min) { + if (rho_iter > mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + // u REGION 2 + } else if (u <= mat->u_cv) { + if (curve == Til_region_hybrid_min) { + if (rho_iter > mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + } else if (curve == Til_region_hybrid) { + if (rho_iter < mat->eta_min * mat->rho_0) { + rho_iter = mat->eta_min * mat->rho_0; + } + if (rho_iter > mat->rho_0) { + rho_iter = mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->rho_0) { + rho_iter = mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + + // u REGION 3 + } else { + if (curve == Til_region_hot) { + if (rho_iter > mat->rho_0) { + rho_iter = mat->rho_0; + } + } else if (curve == Til_region_cold) { + if (rho_iter < mat->rho_0) { + rho_iter = mat->rho_0; + } + } else { + error("Error in Til_density_from_pressure_and_internal_energy"); + } + } + + // Either we've converged ... + if (fabsf(P_fraction) < tol) { + return rho_iter; + + // ... or we're stuck at the boundary ... + } else if (rho_iter == last_rho_iter) { + break; + } + + // ... or we loop again + last_rho_iter = rho_iter; + } + } + return rho_sph; +} + #endif /* SWIFT_TILLOTSON_EQUATION_OF_STATE_H */ diff --git a/src/utilities.h b/src/utilities.h index 28faf6b1e59159af4ee4a7b87054ab6a36478c9c..747ef2154ed2d0b09c22208d3c88aa8a15fcbd3c 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -56,4 +56,47 @@ INLINE static int find_value_in_monot_incr_array(const float x, return index_low; } +/** + * @brief Search for a value in a monotonically increasing array to find the + * index such that table[i,j] = array[i*n_col + j] < value < + * table[i + 1, j] = array[(i + 1)*n_col + j] + * + * @param x The value to find + * @param array The array to search + * @param n_row The number of rows of the table + * @param n_col The number of columns of the table + * @param j The column index to perform the search + * + * Return -1 and n for x below and above the array edge values respectively. + */ +INLINE static int vertical_find_value_in_monot_incr_array(const float x, + const float *array, + const int n_row, + const int n_col, + const int j) { + + int i_low = 0; + int i_high = n_row - 1; + int i_mid; + + // Until table[i_low,j] < x < table[i_high=i_low + 1, j] + while (i_high - i_low > 1) { + i_mid = (i_high + i_low) / 2; // Middle index + + // Replace the low or high i with the middle + if (array[i_mid * n_col + j] <= x) + i_low = i_mid; + else + i_high = i_mid; + } + + // Set index with the found i_low or an error value if outside the array + if (x < array[j]) + return -1; + else if (array[(n_row - 1) * n_col + j] <= x) + return n_row; + else + return i_low; +} + #endif /* SWIFT_UTILITIES_H */