/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2019 Matthieu Schaller (schaller@strw.leidenunuiv.nl) * 2020 Camila Correa (c.a.correa@uva.nl) * * 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 . * ******************************************************************************/ #ifndef SWIFT_CHEMISTRY_IO_COLIBRE_H #define SWIFT_CHEMISTRY_IO_COLIBRE_H #include "chemistry.h" #include "dust_io.h" #include "engine.h" #include "io_properties.h" /** * @brief Specifies which particle fields to read from a dataset * * @param parts The particle array. * @param list The list of i/o properties to read. * * @return Returns the number of fields to read. */ INLINE static int chemistry_read_particles(struct part* parts, struct io_props* list) { /* List what we want to read */ list[0] = io_make_input_field( "ElementAbundance", FLOAT, chemistry_element_count, OPTIONAL, UNIT_CONV_NO_UNITS, parts, chemistry_data.metal_mass_fraction); list[1] = io_make_input_field("Metallicity", FLOAT, 1, OPTIONAL, UNIT_CONV_NO_UNITS, parts, chemistry_data.metal_mass_fraction_total); list[2] = io_make_input_field("IronMassFracFromSNIa", FLOAT, 1, OPTIONAL, UNIT_CONV_NO_UNITS, parts, chemistry_data.iron_mass_fraction_from_SNIa); return 3; } /** * @brief Specifies which particle fields to write to a dataset * * @param parts The particle array. * @param list The list of i/o properties to write. * * @return Returns the number of fields to write. */ INLINE static int chemistry_write_particles(const struct part* parts, const struct xpart* xparts, struct io_props* list, const int with_cosmology) { /* List what we want to write */ list[0] = io_make_output_field_convert_part( "ElementMassFractions", FLOAT, chemistry_element_count, UNIT_CONV_NO_UNITS, 0.f, parts, xparts, convert_part_add_back_dust_for_chemistry, "Fractions of the particles' masses that are in the given element"); list[1] = io_make_output_field_convert_part( "ReducedElementMassFractions", FLOAT, 2, UNIT_CONV_NO_UNITS, 0.f, parts, xparts, convert_part_add_back_dust_for_reduced_chemistry, "Fractions of the particles' masses that are in the given element"); list[2] = io_make_output_field( "MetalMassFractions", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_mass_fraction_total, "Fractions of the particles' masses that are in metals " "(incorporating both depleted and nebular phases)"); list[3] = io_make_output_field("MassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_SNIa, "Fractions of the particles' masses that have " "been produced by SNIa stars"); list[4] = io_make_output_field("MetalMassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_mass_fraction_from_SNIa, "Fractions of the particles' masses that " "are in metals produced by SNIa stars " "(incorporating both depleted and nebular " "phases)"); list[5] = io_make_output_field("MassFractionsFromAGB", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_AGB, "Fractions of the particles' masses that have been " "produced by AGN stars"); list[6] = io_make_output_field("MetalMassFractionsFromAGB", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_mass_fraction_from_AGB, "Fractions of the particles' masses that are " "in metals produced by AGB stars " "(incorporating both depleted and nebular " "phases)"); list[7] = io_make_output_field("MassFractionsFromSNII", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_SNII, "Fractions of the particles' masses that have " "been produced by SNII stars"); list[8] = io_make_output_field("MetalMassFractionsFromSNII", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_mass_fraction_from_SNII, "Fractions of the particles' masses that " "are in metals produced by SNII stars " "(incorporating both depleted and nebular " "phases)"); list[9] = io_make_output_field_convert_part( "IronMassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, xparts, convert_part_add_back_dust_for_snia_iron, "Fractions of the particles' masses that are in iron produced by " "SNIa stars (incorporating both depleted and nebular phases)" "Fractions of the particles' masses that are in metals " "(incorporating both depleted and nebular phases)"); list[10] = io_make_output_field( "MetalDiffusionCoefficients", FLOAT, 1, UNIT_CONV_DIFF_COEFF, 0.f, parts, chemistry_data.diffusion_coefficient, "Metal diffusion coefficients of the particles." "Controls the metal diffusion rate, not to be confused " "with the energy diffusion coefficient. Stored in " "physical co-ordinates"); list[11] = io_make_physical_output_field( "MetalDiffusionRates", FLOAT, chemistry_element_count, UNIT_CONV_DIFF_RATE, 0.f, parts, chemistry_data.diffusion_rate, /*can convert to comoving=*/0, "Metal diffusion rates for each element in physical co-ordinates"); if (with_cosmology) { list[12] = io_make_physical_output_field( "MeanMetalWeightedRedshifts", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.metal_weighted_redshift, /*can convert to comoving=*/0, "Mean redshift of enrichment events weighted by the metal mass " "imparted by each event. -1 if a particle has never been enriched."); list[13] = io_make_physical_output_field( "MeanIronWeightedRedshifts", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.iron_weighted_redshift, /*can convert to comoving=*/0, "Mean redshift of SNIa events weighted by the iron mass imparted by " "each event. -1 if a particle has never been enriched by SNIa."); } else { list[12] = io_make_output_field("MeanMetalWeightedTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, parts, chemistry_data.metal_weighted_redshift, "Mean time of enrichment events weighted by the " "metal mass imparted by each event. -1 if a " "particle has never been enriched."); list[13] = io_make_output_field("MeanIronWeightedTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, parts, chemistry_data.iron_weighted_redshift, "Mean time of SNIa events weighted by the iron " "mass imparted by each event. -1 if a particle " "has never been enriched by SNIa."); } list[14] = io_make_output_field("MassFractionsFromNSM", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_NSM, "Fractions of the particles' masses that have been " "produced by neutron star merger events"); list[15] = io_make_output_field( "MassFractionsFromCEJSN", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_CEJSN, "Fractions of the particles' masses that have been produced by " "common-envelop jets SN events"); list[16] = io_make_output_field("MassFractionsFromCollapsar", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, chemistry_data.mass_fraction_from_collapsar, "Fractions of the particles' masses that " "have been produced by collapsar events"); #if !defined(DUST_NONE) list[17] = io_make_output_field_convert_part( "ElementMassFractionsDiffuse", FLOAT, chemistry_element_count, UNIT_CONV_NO_UNITS, 0.f, parts, xparts, convert_part_diffuse_element_mass_fractions, "Fractions of the particles' masses that are in the given element " "and in the diffuse (non-dust) phase"); list[18] = io_make_output_field_convert_part( "IronMassFractionsFromSNIaDiffuse", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, parts, xparts, convert_part_diffuse_snia_iron, "Fractions of the particles' masses that are in iron originating from " "SNIa, but not depleted into dust"); return 19; #else return 17; #endif } /** * @brief Specifies which sink fields to write to a dataset * * @param sinks The #sink array. * @param list The list of i/o properties to write. * * @return Returns the number of fields to write. */ INLINE static int chemistry_write_sinkparticles(const struct sink* sinks, struct io_props* list) { return 0; } /** * @brief Specifies which star particle fields to write to a dataset * * @param sparts The star particle array. * @param list The list of i/o properties to write. * * @return Returns the number of fields to write. */ INLINE static int chemistry_write_sparticles(const struct spart* sparts, struct io_props* list) { /* List what we want to write */ list[0] = io_make_output_field( "ElementMassFractions", FLOAT, chemistry_element_count, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction, "Fractions of the particles' masses that are in the given element"); list[1] = io_make_output_field( "MetalMassFractions", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction_total, "Fractions of the particles' masses that are in metals"); list[2] = io_make_output_field("MassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_SNIa, "Fractions of the particles' masses that have " "been produced by SNIa stars"); list[3] = io_make_output_field("MetalMassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction_from_SNIa, "Fractions of the particles' masses that are " "in metals produced by SNIa stars"); list[4] = io_make_output_field("MassFractionsFromAGB", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_AGB, "Fractions of the particles' masses that have been " "produced by AGN stars"); list[5] = io_make_output_field("MetalMassFractionsFromAGB", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction_from_AGB, "Fractions of the particles' masses that are " "in metals produced by AGB stars"); list[6] = io_make_output_field("MassFractionsFromSNII", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_SNII, "Fractions of the particles' masses that have " "been produced by SNII stars"); list[7] = io_make_output_field("MetalMassFractionsFromSNII", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.metal_mass_fraction_from_SNII, "Fractions of the particles' masses that are " "in metals produced by SNII stars"); list[8] = io_make_output_field("IronMassFractionsFromSNIa", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.iron_mass_fraction_from_SNIa, "Fractions of the particles' masses that are " "in iron produced by SNIa stars"); list[9] = io_make_output_field("MassFractionsFromNSM", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_NSM, "Fractions of the particles' masses that have been " "produced by neutron star merger events"); list[10] = io_make_output_field( "MassFractionsFromCEJSN", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_CEJSN, "Fractions of the particles' masses that have been produced by " "common-envelop jets SN events"); list[11] = io_make_output_field("MassFractionsFromCollapsar", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, chemistry_data.mass_fraction_from_collapsar, "Fractions of the particles' masses that " "have been produced by collapsar events"); return 12; } /** * @brief Specifies which black hole particle fields to write to a dataset * * @param bparts The black hole particle array. * @param list The list of i/o properties to write. * * @return Returns the number of fields to write. */ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, struct io_props* list) { /* List what we want to write */ list[0] = io_make_output_field_convert_bpart( "ElementMasses", FLOAT, chemistry_element_count, UNIT_CONV_MASS, 0.f, bparts, convert_bpart_add_back_dust_for_chemistry, "Mass contents of the BH particles in a given element"); list[1] = io_make_output_field( "MetalMasses", FLOAT, chemistry_element_count, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.metal_mass_total, "Mass contents of the BH particles in a metals"); list[2] = io_make_output_field( "MassesFromSNIa", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_SNIa, "Masses of the BH particles that have been produced by SNIa stars"); list[3] = io_make_output_field( "MassesFromSNII", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_SNII, "Masses of the BH particles that have been produced by SNII stars"); list[4] = io_make_output_field( "MassesFromAGB", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_AGB, "Masses of the BH particles that have been produced by AGB stars"); list[5] = io_make_output_field("MetalMassesFromSNIa", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.metal_mass_from_SNIa, "Masses of the BH particles in metals that have " "been produced by SNIa stars"); list[6] = io_make_output_field("MetalMassesFromSNII", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.metal_mass_from_SNII, "Masses of the BH particles in metals that have " "been produced by SNII stars"); list[7] = io_make_output_field("MetalMassesFromAGB", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.metal_mass_from_AGB, "Masses of the BH particles in metals that have " "been produced by AGB stars"); list[8] = io_make_output_field_convert_bpart( "IronMassesFromSNIa", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, convert_bpart_add_back_dust_for_snia_iron, "Masses of the BH particles in iron that have been " "produced by SNIa stars"); list[9] = io_make_output_field("MassesFromNSM", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_NSM, "Masses of the BH particles in europium that have " "been produced by neutron star merger events"); list[10] = io_make_output_field("MassesFromCEJSN", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_CEJSN, "Masses of the BH particles in europium that have " "been produced by common-envelop jets SN events"); list[11] = io_make_output_field("MassesFromCollapsar", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, chemistry_data.mass_from_collapsar, "Masses of the BH particles in europium that have " "been produced by collapsar events"); #if !defined(DUST_NONE) list[12] = io_make_output_field_convert_bpart( "ElementMassesDiffuse", FLOAT, chemistry_element_count, UNIT_CONV_MASS, 0.f, bparts, convert_bpart_diffuse_element_mass_fractions, "Masses of the BH that are in the given element and were in the gas " "phase when accreted"); list[13] = io_make_output_field_convert_bpart( "IronMassesFromSNIaDiffuse", FLOAT, 1, UNIT_CONV_MASS, 0.f, bparts, convert_bpart_diffuse_snia_iron, "Masses of the BH particles in iron that have been produced " "by SNIa stars and were in the gas phase when accreted"); return 14; #else return 12; #endif } #ifdef HAVE_HDF5 /** * @brief Writes the current model of SPH to the file * @param h_grp The HDF5 group in which to write * @param h_grp_columns The HDF5 group containing named columns * @param e The #engine. */ INLINE static void chemistry_write_flavour(hid_t h_grp, hid_t h_grp_columns, const struct engine* e) { io_write_attribute_s(h_grp, "Chemistry Model", "COLIBRE"); /* Create an array of element names */ const int element_name_length = 32; char element_names[chemistry_element_count][element_name_length]; for (int elem = 0; elem < chemistry_element_count; ++elem) { sprintf(element_names[elem], "%s", chemistry_get_element_name((enum chemistry_element)elem)); } /* Add to the named columns */ hsize_t dims[1] = {chemistry_element_count}; hid_t type = H5Tcopy(H5T_C_S1); H5Tset_size(type, element_name_length); hid_t space = H5Screate_simple(1, dims, NULL); hid_t dset = H5Dcreate(h_grp_columns, "ElementMassFractions", type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); H5Dclose(dset); dset = H5Dcreate(h_grp_columns, "ElementMassFractionsDiffuse", type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); H5Dclose(dset); dset = H5Dcreate(h_grp_columns, "MetalDiffusionRates", type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); H5Dclose(dset); /* Same for the reduced arrays in snipshots */ dims[0] = 2; space = H5Screate_simple(1, dims, NULL); dset = H5Dcreate(h_grp_columns, "ReducedElementMassFractions", type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); H5Dclose(dset); /* Cross-check in case someone changed the chemistry_struct order... * Or if the Mendeleev table gets new entries... */ if (chemistry_element_H != 0 || chemistry_element_He != 1) error("Elements not in expected order!"); H5Tclose(type); H5Sclose(space); } #endif #endif /* SWIFT_CHEMISTRY_IO_COLIBRE_H */