/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2025 Zachary Rey (zachary.rey@epfl.ch)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Include Header*/
#include "stellar_wind.h"
#include "interpolation.h"
#include
#include
// #include "unit.h"
// TODO: Do we want to print properties of the stellar wind?
/**
* @brief Read an array of stellar wind from the table.
*
* @param sw The #stellar_wind model.
* @param interp Interpolation data to initialize.
* @param sm * The #stellar_model.
* @param group_id The HDF5 group id where to read from.
* @param hdf5_dataset_name The dataset name to read.
* @param previous_count Number of element in the previous array read.
* @param interpolation_size_m Number of element to keep in the mass
* interpolation data.
* @param interpolation_size_z Number of element to keep in the metallicity
* interpolation data.
*/
void stellar_wind_read_yields_array(
struct stellar_wind *sw, struct interpolation_2d *interp,
const struct stellar_model *sm, hid_t group_id,
const char *hdf5_dataset_name, hsize_t *previous_count,
int interpolation_size_m, int interpolation_size_z) {
/* Now let's get the number of elements */
/* Open attribute */
const hid_t h_dataset = H5Dopen(group_id, hdf5_dataset_name, H5P_DEFAULT);
if (h_dataset < 0)
error("Error while opening attribute '%s'", hdf5_dataset_name);
/* Get the number of elements */
hsize_t count = io_get_number_element_in_dataset(h_dataset);
/* Check that all the arrays have the same size */
if (*previous_count != 0 && count != *previous_count) {
error("The code is not able to deal with yields arrays of different size");
}
*previous_count = count;
/* Read the minimal mass (in log) */
float log_mass_min = 0;
io_read_attribute(h_dataset, "m0", FLOAT, &log_mass_min);
/* Read the step size in mass array (log step) */
float step_size_m = 0;
io_read_attribute(h_dataset, "dm", FLOAT, &step_size_m);
/* Read the number of element in mass array */
int Nm = 0;
io_read_attribute(h_dataset, "nm", INT, &Nm);
/* Read the minimal metallicity (in log) */
float log_metallicity_min = 0;
io_read_attribute(h_dataset, "z0", FLOAT, &log_metallicity_min);
/* Read the step size in metallicity array (log step) */
float step_size_z = 0;
io_read_attribute(h_dataset, "dz", FLOAT, &step_size_z);
/* Read the number of element in metallicity array */
int Nz = 0;
io_read_attribute(h_dataset, "nz", INT, &Nz);
/* Close the attribute */
H5Dclose(h_dataset);
/* Allocate the memory */
double *data = (double *)malloc(sizeof(double) * Nz * Nm);
if (data == NULL)
error("Failed to allocate the SW yields for %s.", hdf5_dataset_name);
/* Read the dataset */
io_read_array_dataset(group_id, hdf5_dataset_name, DOUBLE, data, count);
/* Initialize the raw interpolation */
float log_mass_max = log_mass_min + step_size_m * Nm;
float log_metallicity_max = log_metallicity_min + step_size_z * Nz;
interpolate_2d_init(interp, log_metallicity_min, log_metallicity_max,
interpolation_size_z, log_mass_min, log_mass_max,
interpolation_size_m, log_metallicity_min, log_mass_min,
step_size_z, step_size_m, Nz, Nm, data,
boundary_condition_const);
/* Cleanup the memory */
free(data);
}
/**
* @brief Read the SW yields from the table.
*
* The tables are in [erg/yr] units at the end of this function. TODO: convert
* into internal units
*
* @param sw The #stellar_wind model.
* @param params The simulation parameters.
* @param sm The #stellar_model.
* @param restart Are we restarting the simulation? (Is params NULL?)
*/
void stellar_wind_read_yields(struct stellar_wind *sw,
struct swift_params *params,
const struct stellar_model *sm,
const int restart) {
hid_t file_id, group_id;
hsize_t previous_count = 0;
if (!restart) {
sw->interpolation_size_m = parser_get_opt_param_int(
params, "GEARStellar_wind:interpolation_size_mass", 200);
sw->interpolation_size_z = parser_get_opt_param_int(
params, "GEARStellar_wind:interpolation_size_metallicity", 110);
}
/* Open IMF group */
h5_open_group(sm->yields_table, "Data/SW/MetallicityDependent", &file_id,
&group_id);
/* Read the energy*/
stellar_wind_read_yields_array(
sw, &sw->raw.ejected_energy, sm, group_id, "Energy", &previous_count,
sw->interpolation_size_m, sw->interpolation_size_z);
/* Read the integrated energy*/
stellar_wind_read_yields_array(
sw, &sw->integrated.ejected_energy_per_progenitor_mass, sm, group_id,
"Integrated_Energy", &previous_count, sw->interpolation_size_m,
sw->interpolation_size_z);
/* Read the mass-loss*/
stellar_wind_read_yields_array(
sw, &sw->raw.mass_loss, sm, group_id, "Mass_Loss", &previous_count,
sw->interpolation_size_m, sw->interpolation_size_z);
/* Read the integrated mass-loss*/
stellar_wind_read_yields_array(
sw, &sw->integrated.mass_loss_per_progenitor_mass, sm, group_id,
"Integrated_Mass_Loss", &previous_count, sw->interpolation_size_m,
sw->interpolation_size_z);
/* Cleanup everything */
h5_close_group(file_id, group_id);
};
/**
* @brief Initialize the #stellar_wind structure.
*
* @param sw The #stellar_wind model.
* @param params The simulation parameters.
* @param sm The #stellar_model.
* @param us The unit system.
*/
void stellar_wind_init(struct stellar_wind *sw, struct swift_params *params,
const struct stellar_model *sm,
const struct unit_system *us) {
/* Read the stellar wind yields */
stellar_wind_read_yields(sw, params, sm, /* restart */ 0);
}
/**
* @brief Get the ejected energy given a discrete mass.
*
* @param sw The #stellar_wind model.
* @param log_m The upper mass in log.
* @param log_z The metallicity in log.
*
* @return energy per unit time in [erg/yr].
*/
double stellar_wind_get_ejected_energy(const struct stellar_wind *sw,
float log_m, float log_z) {
return pow(10, interpolate_2d(&sw->raw.ejected_energy, log_z, log_m));
};
/**
* @brief Get the ejected energy per progenitor mass.
*
* @param sw The #stellar_wind model.
* @param log_m The upper mass in log.
* @param log_z The metallicity in log.
*
* @return energy per progenitor mass per unit time in [erg/yr].
*/
double stellar_wind_get_ejected_energy_IMF(const struct stellar_wind *sw,
float log_m, float log_z) {
return pow(10,
interpolate_2d(&sw->integrated.ejected_energy_per_progenitor_mass,
log_z, log_m));
};
/**
* @brief Get the ejected mass given a discrete mass.
*
* @param sw The #stellar_wind model.
* @param log_m The upper mass in log.
* @param log_z The metallicity in log.
*
* @return mass per unit time in [Msol/yr].
*/
double stellar_wind_get_ejected_mass(const struct stellar_wind *sw, float log_m,
float log_z) {
return pow(10, interpolate_2d(&sw->raw.mass_loss, log_z, log_m));
};
/**
* @brief Get the ejected mass per progenitor mass.
*
* @param sw The #stellar_wind model.
* @param log_m The upper mass in log.
* @param log_z The metallicity in log.
*
* @return mass per progenitor mass per unit time in [Msol/yr].
*/
double stellar_wind_get_ejected_mass_IMF(const struct stellar_wind *sw,
float log_m, float log_z) {
return pow(10, interpolate_2d(&sw->integrated.mass_loss_per_progenitor_mass,
log_z, log_m));
};
/**
* @brief Clean the allocated memory.
*
* @param sw the #stellar_wind.
*/
void stellar_wind_clean(struct stellar_wind *sw) {
interpolate_2d_free(&sw->integrated.ejected_energy_per_progenitor_mass);
interpolate_2d_free(&sw->raw.ejected_energy);
interpolate_2d_free(&sw->raw.mass_loss);
interpolate_2d_free(&sw->integrated.mass_loss_per_progenitor_mass);
}