MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
Classes | Macros | Functions | Variables
metal_return.c File Reference

Compute the mass return rate of metals from stellar evolution. More...

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_interp2d.h>
#include <gsl/gsl_roots.h>
#include <gsl/gsl_errno.h>
#include <omp.h>
#include "physconst.h"
#include "walltime.h"
#include "slotsmanager.h"
#include "treewalk.h"
#include "metal_return.h"
#include "densitykernel.h"
#include "density.h"
#include "cosmology.h"
#include "winds.h"
#include "utils/spinlocks.h"
#include "metal_tables.h"
Include dependency graph for metal_return.c:

Go to the source code of this file.

Classes

struct  metal_return_params
 
struct  TreeWalkQueryMetals
 
struct  TreeWalkResultMetals
 
struct  TreeWalkNgbIterMetals
 
struct  massbin_find_params
 
struct  imf_integ_params
 
struct  TreeWalkNgbIterStellarDensity
 
struct  TreeWalkQueryStellarDensity
 
struct  TreeWalkResultStellarDensity
 
struct  StellarDensityPriv
 

Macros

#define METALS_GET_PRIV(tw)   ((struct MetalReturnPriv*) ((tw)->priv))
 
#define NHSML   10
 
#define STELLAR_DENSITY_GET_PRIV(tw)   ((struct StellarDensityPriv*) ((tw)->priv))
 

Functions

void set_metal_params (double Sn1aN0)
 
void set_metal_return_params (ParameterSet *ps)
 
void setup_metal_table_interp (struct interps *interp)
 
static int metal_return_haswork (int n, TreeWalk *tw)
 
static void metal_return_ngbiter (TreeWalkQueryMetals *I, TreeWalkResultMetals *O, TreeWalkNgbIterMetals *iter, LocalTreeWalk *lv)
 
static void metal_return_copy (int place, TreeWalkQueryMetals *input, TreeWalk *tw)
 
static void metal_return_postprocess (int place, TreeWalk *tw)
 
static double chabrier_imf (double mass)
 
double atime_integ (double atime, void *params)
 
static double atime_to_myr (Cosmology *CP, double atime1, double atime2, gsl_integration_workspace *gsl_work)
 
double massendlife (double mass, void *params)
 
double do_rootfinding (struct massbin_find_params *p, double mass_low, double mass_high)
 
void find_mass_bin_limits (double *masslow, double *masshigh, const double dtstart, const double dtend, double stellarmetal, gsl_interp2d *lifetime_tables)
 
double chabrier_imf_integ (double mass, void *params)
 
double chabrier_mass (double mass, void *params)
 
double compute_imf_norm (gsl_integration_workspace *gsl_work)
 
double sn1a_number (double dtmyrstart, double dtmyrend, double hub)
 
double compute_agb_yield (gsl_interp2d *agb_interp, const double *agb_weights, double stellarmetal, double masslow, double masshigh, gsl_integration_workspace *gsl_work)
 
double compute_snii_yield (gsl_interp2d *snii_interp, const double *snii_weights, double stellarmetal, double masslow, double masshigh, gsl_integration_workspace *gsl_work)
 
static double mass_yield (double dtmyrstart, double dtmyrend, double stellarmetal, double hub, struct interps *interp, double imf_norm, gsl_integration_workspace *gsl_work, double masslow, double masshigh)
 
static double metal_yield (double dtmyrstart, double dtmyrend, double stellarmetal, double hub, struct interps *interp, MyFloat *MetalYields, double imf_norm, gsl_integration_workspace *gsl_work, double masslow, double masshigh)
 
int64_t metal_return_init (const ActiveParticles *act, Cosmology *CP, struct MetalReturnPriv *priv, const double atime)
 
void metal_return_priv_free (struct MetalReturnPriv *priv)
 
void metal_return (const ActiveParticles *act, DomainDecomp *const ddecomp, Cosmology *CP, const double atime, const double AvgGasMass)
 
int metals_haswork (int i, MyFloat *MassReturn)
 
static int stellar_density_haswork (int i, TreeWalk *tw)
 
static double effhsml (int place, int i, TreeWalk *tw)
 
static void stellar_density_copy (int place, TreeWalkQueryStellarDensity *I, TreeWalk *tw)
 
static void stellar_density_reduce (int place, TreeWalkResultStellarDensity *remote, enum TreeWalkReduceMode mode, TreeWalk *tw)
 
void stellar_density_check_neighbours (int i, TreeWalk *tw)
 
static void stellar_density_ngbiter (TreeWalkQueryStellarDensity *I, TreeWalkResultStellarDensity *O, TreeWalkNgbIterStellarDensity *iter, LocalTreeWalk *lv)
 
void stellar_density (const ActiveParticles *act, MyFloat *StarVolumeSPH, MyFloat *MassReturn, const ForceTree *const tree)
 

Variables

static struct metal_return_params MetalParams
 

Detailed Description

Compute the mass return rate of metals from stellar evolution.

This file returns metals from stars with some delay. Delayed sources followed are AGB stars, SNII and Sn1a. 9 Species specific yields are stored in the stars and the gas particles. Gas enrichment is not run every timestep, but only for stars that have significant enrichment, or are young. The model closely follows Illustris-TNG, https://arxiv.org/abs/1703.02970 However the tables used are slightly different: we consider SNII between 8 and 40 Msun following Kobayashi 2006, where they use a hybrid of Kobayashi and Portinari. AGB yields are from Karakas 2010, like TNG, but stars with mass > 6.5 are from Doherty 2014, not Fishlock 2014. More details of the model can be found in the Illustris model Vogelsberger 2013: https://arxiv.org/abs/1305.2913 As the Kobayashi table only goes to 13 Msun, stars with masses 8-13 Msun are assumed to yield like a 13 Msun star, but scaled by a factor of (M/13).

Definition in file metal_return.c.

Macro Definition Documentation

◆ METALS_GET_PRIV

#define METALS_GET_PRIV (   tw)    ((struct MetalReturnPriv*) ((tw)->priv))

Definition at line 99 of file metal_return.c.

◆ NHSML

#define NHSML   10

Definition at line 726 of file metal_return.c.

◆ STELLAR_DENSITY_GET_PRIV

#define STELLAR_DENSITY_GET_PRIV (   tw)    ((struct StellarDensityPriv*) ((tw)->priv))

Definition at line 762 of file metal_return.c.

Function Documentation

◆ atime_integ()

double atime_integ ( double  atime,
void *  params 
)

Definition at line 154 of file metal_return.c.

155 {
156  Cosmology * CP = (Cosmology *) params;
157  return 1/(hubble_function(CP, atime) * atime);
158 }
double hubble_function(const Cosmology *CP, double a)
Definition: cosmology.c:58
static Cosmology * CP
Definition: power.c:27

References CP, and hubble_function().

Referenced by atime_to_myr().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ atime_to_myr()

static double atime_to_myr ( Cosmology CP,
double  atime1,
double  atime2,
gsl_integration_workspace *  gsl_work 
)
static

Definition at line 161 of file metal_return.c.

162 {
163  /* t = dt/da da = 1/(Ha) da*/
164  /* Approximate hubble function as constant here: we only care
165  * about metal return over a single timestep*/
166  gsl_function ff = {atime_integ, CP};
167  double tmyr, abserr;
168  gsl_integration_qag(&ff, atime1, atime2, 1e-4, 0, GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &tmyr, &abserr);
169  return tmyr * CP->UnitTime_in_s / SEC_PER_MEGAYEAR;
170 }
double atime_integ(double atime, void *params)
Definition: metal_return.c:154
#define GSL_WORKSPACE
Definition: metal_tables.h:426
#define SEC_PER_MEGAYEAR
Definition: physconst.h:31
double UnitTime_in_s
Definition: cosmology.h:22

References atime_integ(), CP, GSL_WORKSPACE, SEC_PER_MEGAYEAR, and Cosmology::UnitTime_in_s.

Referenced by metal_return_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ chabrier_imf()

static double chabrier_imf ( double  mass)
static

Definition at line 144 of file metal_return.c.

145 {
146  if(mass <= 1) {
147  return 0.852464 / mass * exp(- pow(log(mass / 0.079)/ 0.69, 2)/2);
148  }
149  else {
150  return 0.237912 * pow(mass, -2.3);
151  }
152 }

Referenced by chabrier_imf_integ(), and chabrier_mass().

Here is the caller graph for this function:

◆ chabrier_imf_integ()

double chabrier_imf_integ ( double  mass,
void *  params 
)

Definition at line 289 of file metal_return.c.

290 {
291  struct imf_integ_params * para = (struct imf_integ_params * ) params;
292  /* This is needed so that the yield for SNII with masses between 8 and 13 Msun
293  * are the same as the smallest mass in the table, 13 Msun,
294  * but they still contribute their number density to the IMF.*/
295  double intpmass = mass;
296  if(mass < para->masses[0])
297  intpmass = para->masses[0];
298  if(mass > para->masses[para->interp->ysize-1])
299  intpmass = para->masses[para->interp->ysize-1];
300  double weight = gsl_interp2d_eval(para->interp, para->metallicities, para->masses, para->weights, para->metallicity, intpmass, NULL, NULL);
301  /* This rescales the return by the original mass of the star, if it was outside the table.
302  * It means that, for example, an 8 Msun star does not return more than 8 Msun. */
303  weight *= (mass/intpmass);
304  return weight * chabrier_imf(mass);
305 }
static double chabrier_imf(double mass)
Definition: metal_return.c:144
const double * metallicities
Definition: metal_return.c:283
const double * weights
Definition: metal_return.c:284
gsl_interp2d * interp
Definition: metal_return.c:281
const double * masses
Definition: metal_return.c:282

References chabrier_imf(), imf_integ_params::interp, imf_integ_params::masses, imf_integ_params::metallicities, imf_integ_params::metallicity, and imf_integ_params::weights.

Referenced by compute_agb_yield(), and compute_snii_yield().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ chabrier_mass()

double chabrier_mass ( double  mass,
void *  params 
)

Definition at line 308 of file metal_return.c.

309 {
310  return mass * chabrier_imf(mass);
311 }

References chabrier_imf().

Referenced by compute_imf_norm(), and test_yields().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_agb_yield()

double compute_agb_yield ( gsl_interp2d *  agb_interp,
const double *  agb_weights,
double  stellarmetal,
double  masslow,
double  masshigh,
gsl_integration_workspace *  gsl_work 
)

Definition at line 342 of file metal_return.c.

343 {
344  struct imf_integ_params para;
345  gsl_function ff = {chabrier_imf_integ, &para};
346  double agbyield = 0, abserr;
347  /* Only return AGB metals for the range of AGB stars*/
348  if (masshigh > SNAGBSWITCH)
349  masshigh = SNAGBSWITCH;
350  if (masslow < agb_masses[0])
351  masslow = agb_masses[0];
352  if (stellarmetal > agb_metallicities[AGB_NMET-1])
353  stellarmetal = agb_metallicities[AGB_NMET-1];
354  if (stellarmetal < agb_metallicities[0])
355  stellarmetal = agb_metallicities[0];
356  /* This happens if no bins in range had dying stars this timestep*/
357  if(masslow >= masshigh)
358  return 0;
359  para.interp = agb_interp;
360  para.masses = agb_masses;
361  para.metallicities = agb_metallicities;
362  para.metallicity = stellarmetal;
363  para.weights = agb_weights;
364  gsl_integration_qag(&ff, masslow, masshigh, 1e-7, 1e-3, GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &agbyield, &abserr);
365  return agbyield;
366 }
double chabrier_imf_integ(double mass, void *params)
Definition: metal_return.c:289
#define AGB_NMET
Definition: metal_tables.h:68
static const double agb_masses[AGB_NMASS]
Definition: metal_tables.h:70
#define SNAGBSWITCH
Definition: metal_tables.h:13
static const double agb_metallicities[AGB_NMET]
Definition: metal_tables.h:71

References agb_masses, agb_metallicities, AGB_NMET, chabrier_imf_integ(), GSL_WORKSPACE, imf_integ_params::interp, imf_integ_params::masses, imf_integ_params::metallicities, imf_integ_params::metallicity, SNAGBSWITCH, and imf_integ_params::weights.

Referenced by mass_yield(), metal_yield(), and test_yields().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_imf_norm()

double compute_imf_norm ( gsl_integration_workspace *  gsl_work)

Definition at line 314 of file metal_return.c.

315 {
316  double norm, abserr;
317  gsl_function ff = {chabrier_mass, NULL};
318  gsl_integration_qag(&ff, MINMASS, MAXMASS, 1e-4, 1e-3, GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &norm, &abserr);
319  return norm;
320 }
double chabrier_mass(double mass, void *params)
Definition: metal_return.c:308
#define MINMASS
Definition: metal_tables.h:11
#define MAXMASS
Definition: metal_tables.h:9

References chabrier_mass(), GSL_WORKSPACE, MAXMASS, and MINMASS.

Referenced by metal_return_init(), and test_yields().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_snii_yield()

double compute_snii_yield ( gsl_interp2d *  snii_interp,
const double *  snii_weights,
double  stellarmetal,
double  masslow,
double  masshigh,
gsl_integration_workspace *  gsl_work 
)

Definition at line 368 of file metal_return.c.

369 {
370  struct imf_integ_params para;
371  gsl_function ff = {chabrier_imf_integ, &para};
372  double yield = 0, abserr;
373  /* Only return metals for the range of SNII stars.*/
374  if (masshigh > snii_masses[SNII_NMASS-1])
375  masshigh = snii_masses[SNII_NMASS-1];
376  if (masslow < SNAGBSWITCH)
377  masslow = SNAGBSWITCH;
378  if (stellarmetal > snii_metallicities[SNII_NMET-1])
379  stellarmetal = snii_metallicities[SNII_NMET-1];
380  if (stellarmetal < snii_metallicities[0])
381  stellarmetal = snii_metallicities[0];
382  para.interp = snii_interp;
383  para.masses = snii_masses;
384  para.metallicities = snii_metallicities;
385  para.metallicity = stellarmetal;
386  para.weights = snii_weights;
387  /* This happens if no bins in range had dying stars this timestep*/
388  if(masslow >= masshigh)
389  return 0;
390  gsl_integration_qag(&ff, masslow, masshigh, 1e-7, 1e-3, GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &yield, &abserr);
391  return yield;
392 }
static const double snii_metallicities[SNII_NMET]
Definition: metal_tables.h:311
#define SNII_NMASS
Definition: metal_tables.h:309
#define SNII_NMET
Definition: metal_tables.h:308
static const double snii_masses[SNII_NMASS]
Definition: metal_tables.h:310

References chabrier_imf_integ(), GSL_WORKSPACE, imf_integ_params::interp, imf_integ_params::masses, imf_integ_params::metallicities, imf_integ_params::metallicity, SNAGBSWITCH, snii_masses, snii_metallicities, SNII_NMASS, SNII_NMET, and imf_integ_params::weights.

Referenced by mass_yield(), metal_yield(), and test_yields().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_rootfinding()

double do_rootfinding ( struct massbin_find_params p,
double  mass_low,
double  mass_high 
)

Definition at line 194 of file metal_return.c.

195 {
196  int iter = 0;
197  gsl_function F;
198 
199  F.function = &massendlife;
200  F.params = p;
201 
202  const gsl_root_fsolver_type *T = gsl_root_fsolver_falsepos;
203  gsl_root_fsolver * s = gsl_root_fsolver_alloc (T);
204  gsl_root_fsolver_set (s, &F, mass_low, mass_high);
205 
206  /* Iterate until we have an idea of the mass bins dying this timestep.
207  * No check is done for success, but it should always be close enough.*/
208  for(iter = 0; iter < MAXITER; iter++)
209  {
210  gsl_root_fsolver_iterate (s);
211  mass_low = gsl_root_fsolver_x_lower (s);
212  mass_high = gsl_root_fsolver_x_upper (s);
213  int status = gsl_root_test_interval (mass_low, mass_high,
214  0, 0.005);
215  //message(4, "lo %g hi %g root %g val %g\n", mass_low, mass_high, gsl_root_fsolver_root(s), massendlife(gsl_root_fsolver_root(s), p));
216  if (status == GSL_SUCCESS)
217  break;
218  }
219  double root = gsl_root_fsolver_root(s);
220  gsl_root_fsolver_free (s);
221  return root;
222 }
#define MAXITER
Definition: cooling.c:46
double massendlife(double mass, void *params)
Definition: metal_return.c:185

References massendlife(), and MAXITER.

Referenced by find_mass_bin_limits().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ effhsml()

static double effhsml ( int  place,
int  i,
TreeWalk tw 
)
inlinestatic

Definition at line 772 of file metal_return.c.

773 {
774  int pi = P[place].PI;
775  double left = STELLAR_DENSITY_GET_PRIV(tw)->Left[pi];
776  double right = STELLAR_DENSITY_GET_PRIV(tw)->Right[pi];
777  /* If somehow Hsml has become zero through underflow, use something non-zero
778  * to make sure we converge. */
779  if(left == 0 && right > 0.99*tw->tree->BoxSize && P[place].Hsml == 0) {
780  int fat = force_get_father(place, tw->tree);
781  P[place].Hsml = tw->tree->Nodes[fat].len;
782  if(P[place].Hsml == 0)
783  P[place].Hsml = tw->tree->BoxSize / pow(PartManager->NumPart, 1./3)/4.;
784  }
785  /* Use slightly past the current Hsml as the right most boundary*/
786  if(right > 0.99*tw->tree->BoxSize)
787  right = P[place].Hsml * ((1.+NHSML)/NHSML);
788  /* Use 1/2 of current Hsml for left. The asymmetry is because it is free
789  * to compute extra densities for h < Hsml, but not for h > Hsml.*/
790  if(left == 0)
791  left = 0.1 * P[place].Hsml;
792  /* From left + 1/N to right - 1/N, evenly spaced in volume,
793  * since NumNgb ~ h^3.*/
794  double rvol = pow(right, 3);
795  double lvol = pow(left, 3);
796  return pow((1.*i+1)/(1.*NHSML+1) * (rvol - lvol) + lvol, 1./3);
797 }
int force_get_father(int no, const ForceTree *tree)
Definition: forcetree.c:905
#define STELLAR_DENSITY_GET_PRIV(tw)
Definition: metal_return.c:762
#define NHSML
Definition: metal_return.c:726
struct part_manager_type PartManager[1]
Definition: partmanager.c:11
#define P
Definition: partmanager.h:88
double BoxSize
Definition: forcetree.h:106
struct NODE * Nodes
Definition: forcetree.h:97
MyFloat len
Definition: forcetree.h:42
const ForceTree * tree
Definition: treewalk.h:88

References ForceTree::BoxSize, force_get_father(), NODE::len, NHSML, ForceTree::Nodes, part_manager_type::NumPart, P, PartManager, STELLAR_DENSITY_GET_PRIV, and TreeWalk::tree.

Referenced by stellar_density_check_neighbours(), and stellar_density_copy().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_mass_bin_limits()

void find_mass_bin_limits ( double *  masslow,
double *  masshigh,
const double  dtstart,
const double  dtend,
double  stellarmetal,
gsl_interp2d *  lifetime_tables 
)

Definition at line 230 of file metal_return.c.

231 {
232  /* Clamp metallicities to the table values.*/
233  if(stellarmetal < lifetime_metallicity[0])
234  stellarmetal = lifetime_metallicity[0];
235  if(stellarmetal > lifetime_metallicity[LIFE_NMET-1])
236  stellarmetal = lifetime_metallicity[LIFE_NMET-1];
237 
238  /* Find the root with GSL routines. */
239  struct massbin_find_params p = {0};
240  p.metalacc = gsl_interp_accel_alloc();
241  p.massacc = gsl_interp_accel_alloc();
244  /* First find stars that died before the end of this timebin*/
245  p.dtfind = dtend;
246  /* If no stars have died yet*/
247  if(massendlife (MAXMASS, &p) >= 0)
248  {
249  *masslow = MAXMASS;
250  *masshigh = MAXMASS;
251  return;
252  }
253  /* All stars die before the end of this timestep*/
254  if(massendlife (agb_masses[0], &p) <= 0)
255  *masslow = lifetime_masses[0];
256  else
257  *masslow = do_rootfinding(&p, agb_masses[0], MAXMASS);
258 
259  /* Now find stars that died before the start of this timebin*/
260  p.dtfind = dtstart;
261  /* Now we know that life(masslow) = dtend, so life(masslow) > dtstart, so life(masslow) - dtstart > 0
262  * This is when no stars have died at the beginning of this timestep.*/
263  if(massendlife (MAXMASS, &p) >= 0)
264  *masshigh = MAXMASS;
265  /* This can sometimes happen due to root finding inaccuracy.
266  * Just do this star next timestep.*/
267  else if(massendlife (*masslow, &p) <= 0)
268  *masshigh = *masslow;
269  else
270  *masshigh = do_rootfinding(&p, *masslow, MAXMASS);
271  gsl_interp_accel_free(p.metalacc);
272  gsl_interp_accel_free(p.massacc);
273 }
double do_rootfinding(struct massbin_find_params *p, double mass_low, double mass_high)
Definition: metal_return.c:194
#define LIFE_NMET
Definition: metal_tables.h:16
static const double lifetime_metallicity[LIFE_NMET]
Definition: metal_tables.h:18
static const double lifetime_masses[LIFE_NMASS]
Definition: metal_tables.h:20
gsl_interp_accel * massacc
Definition: metal_return.c:179
gsl_interp_accel * metalacc
Definition: metal_return.c:178
gsl_interp2d * lifetime_tables
Definition: metal_return.c:177

References agb_masses, do_rootfinding(), massbin_find_params::dtfind, LIFE_NMET, lifetime_masses, lifetime_metallicity, massbin_find_params::lifetime_tables, massbin_find_params::massacc, massendlife(), MAXMASS, massbin_find_params::metalacc, and massbin_find_params::stellarmetal.

Referenced by metal_return_init(), and test_yields().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mass_yield()

static double mass_yield ( double  dtmyrstart,
double  dtmyrend,
double  stellarmetal,
double  hub,
struct interps interp,
double  imf_norm,
gsl_integration_workspace *  gsl_work,
double  masslow,
double  masshigh 
)
static

Definition at line 395 of file metal_return.c.

396 {
397  /* Number of AGB stars/SnII by integrating the IMF*/
398  double agbyield = compute_agb_yield(interp->agb_mass_interp, agb_total_mass, stellarmetal, masslow, masshigh, gsl_work);
399  double sniiyield = compute_snii_yield(interp->snii_mass_interp, snii_total_mass, stellarmetal, masslow, masshigh, gsl_work);
400  /* Fraction of the IMF which goes off this timestep. Normalised by the total IMF so we get a fraction of the SSP.*/
401  double massyield = (agbyield + sniiyield)/imf_norm;
402  /* Mass yield from Sn1a*/
403  double Nsn1a = sn1a_number(dtmyrstart, dtmyrend, hub);
404  massyield += Nsn1a * sn1a_total_metals;
405  //message(3, "masslow %g masshigh %g stellarmetal %g dystart %g dtend %g agb %g snii %g sn1a %g imf_norm %g\n",
406  // masslow, masshigh, stellarmetal, dtmyrstart, dtmyrend, agbyield, sniiyield, Nsn1a * sn1a_total_metals, imf_norm);
407  return massyield;
408 }
Interp interp
double sn1a_number(double dtmyrstart, double dtmyrend, double hub)
Definition: metal_return.c:324
double compute_snii_yield(gsl_interp2d *snii_interp, const double *snii_weights, double stellarmetal, double masslow, double masshigh, gsl_integration_workspace *gsl_work)
Definition: metal_return.c:368
double compute_agb_yield(gsl_interp2d *agb_interp, const double *agb_weights, double stellarmetal, double masslow, double masshigh, gsl_integration_workspace *gsl_work)
Definition: metal_return.c:342
static const double snii_total_mass[SNII_NMET *SNII_NMASS]
Definition: metal_tables.h:312
static const double agb_total_mass[AGB_NMET *AGB_NMASS]
Definition: metal_tables.h:72
static const double sn1a_total_metals
Definition: metal_tables.h:60

References agb_total_mass, compute_agb_yield(), compute_snii_yield(), interp, sn1a_number(), sn1a_total_metals, and snii_total_mass.

Referenced by metal_return_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ massendlife()

double massendlife ( double  mass,
void *  params 
)

Definition at line 185 of file metal_return.c.

186 {
187  struct massbin_find_params *p = (struct massbin_find_params *) params;
188  double tlife = gsl_interp2d_eval(p->lifetime_tables, lifetime_metallicity, lifetime_masses, lifetime, p->stellarmetal, mass, p->metalacc, p->massacc);
189  double tlifemyr = tlife/1e6;
190  return tlifemyr - p->dtfind;
191 }
static const double lifetime[LIFE_NMASS *LIFE_NMET]
Definition: metal_tables.h:24

References massbin_find_params::dtfind, lifetime, lifetime_masses, lifetime_metallicity, massbin_find_params::lifetime_tables, massbin_find_params::massacc, massbin_find_params::metalacc, and massbin_find_params::stellarmetal.

Referenced by do_rootfinding(), and find_mass_bin_limits().

Here is the caller graph for this function:

◆ metal_return()

void metal_return ( const ActiveParticles act,
DomainDecomp *const  ddecomp,
Cosmology CP,
const double  atime,
const double  AvgGasMass 
)

This function is the driver routine for the calculation of metal return.

Definition at line 517 of file metal_return.c.

518 {
519  /* Do nothing if no stars yet*/
520  int64_t totstar;
521  MPI_Allreduce(&SlotsManager->info[4].size, &totstar, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
522  if(totstar == 0)
523  return;
524 
525  struct MetalReturnPriv priv[1];
526 
527  int64_t nwork = metal_return_init(act, CP, priv, atime);
528 
529  /* Maximum mass of a gas particle after enrichment: cap it at a few times the initial mass.
530  * FIXME: Ideally we should here fork a new particle with a smaller gas mass. We should
531  * figure out then how set the gas entropy. A possibly better idea is to add
532  * a generic routine to split gas particles into the density code.*/
533  priv->MaxGasMass = 4* AvgGasMass;
534 
535  int64_t totwork;
536  MPI_Allreduce(&nwork, &totwork, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
537 
538  walltime_measure("/SPH/Metals/Init");
539 
540  if(totwork == 0) {
542  return;
543  }
544 
545  ForceTree gasTree = {0};
546  /* Just gas, no moments*/
547  force_tree_rebuild_mask(&gasTree, ddecomp, GASMASK, 0, NULL);
548 
549  /* Compute total number of weights around each star for actively returning stars*/
550  stellar_density(act, priv->StarVolumeSPH, priv->MassReturn, &gasTree);
551 
552  /* Do the metal return*/
553  TreeWalk tw[1] = {{0}};
554 
555  tw->ev_label = "METALS";
561  tw->reduce = NULL;
565  tw->repeatdisallowed = 1;
566  tw->tree = &gasTree;
567  tw->priv = priv;
568 
569  priv->spin = init_spinlocks(SlotsManager->info[0].size);
571  free_spinlocks(priv->spin);
572 
573  force_tree_free(&gasTree);
575 
576  /* collect some timing information */
577  walltime_measure("/SPH/Metals/Yield");
578 }
void force_tree_rebuild_mask(ForceTree *tree, DomainDecomp *ddecomp, int mask, const int HybridNuGrav, const char *EmergencyOutputDir)
Definition: forcetree.c:161
void force_tree_free(ForceTree *tree)
Definition: forcetree.c:1409
#define GASMASK
Definition: forcetree.h:21
int64_t metal_return_init(const ActiveParticles *act, Cosmology *CP, struct MetalReturnPriv *priv, const double atime)
Definition: metal_return.c:437
static void metal_return_postprocess(int place, TreeWalk *tw)
Definition: metal_return.c:619
void metal_return_priv_free(struct MetalReturnPriv *priv)
Definition: metal_return.c:500
static int metal_return_haswork(int n, TreeWalk *tw)
Definition: metal_return.c:720
void stellar_density(const ActiveParticles *act, MyFloat *StarVolumeSPH, MyFloat *MassReturn, const ForceTree *const tree)
Definition: metal_return.c:923
static void metal_return_copy(int place, TreeWalkQueryMetals *input, TreeWalk *tw)
Definition: metal_return.c:583
static void metal_return_ngbiter(TreeWalkQueryMetals *I, TreeWalkResultMetals *O, TreeWalkNgbIterMetals *iter, LocalTreeWalk *lv)
Definition: metal_return.c:633
struct slots_manager_type SlotsManager[1]
Definition: slotsmanager.c:7
void free_spinlocks(struct SpinLocks *spin)
Definition: spinlocks.c:70
struct SpinLocks * init_spinlocks(int NumLock)
Definition: spinlocks.c:49
int * ActiveParticle
Definition: timestep.h:13
int64_t NumActiveParticle
Definition: timestep.h:12
void * priv
Definition: treewalk.h:85
TreeWalkHasWorkFunction haswork
Definition: treewalk.h:100
size_t ngbiter_type_elsize
Definition: treewalk.h:97
TreeWalkProcessFunction postprocess
Definition: treewalk.h:104
TreeWalkNgbIterFunction ngbiter
Definition: treewalk.h:103
TreeWalkReduceResultFunction reduce
Definition: treewalk.h:102
const char * ev_label
Definition: treewalk.h:91
TreeWalkVisitFunction visit
Definition: treewalk.h:99
int repeatdisallowed
Definition: treewalk.h:117
size_t result_type_elsize
Definition: treewalk.h:96
TreeWalkFillQueryFunction fill
Definition: treewalk.h:101
size_t query_type_elsize
Definition: treewalk.h:95
int64_t size
Definition: slotsmanager.h:12
struct slot_info info[6]
Definition: slotsmanager.h:112
#define MPI_INT64
Definition: system.h:12
int treewalk_visit_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
Definition: treewalk.c:924
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
Definition: treewalk.c:619
int(* TreeWalkVisitFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, LocalTreeWalk *lv)
Definition: treewalk.h:68
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
Definition: treewalk.h:73
void(* TreeWalkNgbIterFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, TreeWalkNgbIterBase *iter, LocalTreeWalk *lv)
Definition: treewalk.h:70
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
Definition: treewalk.h:75
#define walltime_measure(name)
Definition: walltime.h:8

References ActiveParticles::ActiveParticle, CP, TreeWalk::ev_label, TreeWalk::fill, force_tree_free(), force_tree_rebuild_mask(), free_spinlocks(), GASMASK, TreeWalk::haswork, slots_manager_type::info, init_spinlocks(), MetalReturnPriv::MassReturn, MetalReturnPriv::MaxGasMass, metal_return_copy(), metal_return_haswork(), metal_return_init(), metal_return_ngbiter(), metal_return_postprocess(), metal_return_priv_free(), MPI_INT64, TreeWalk::ngbiter, TreeWalk::ngbiter_type_elsize, ActiveParticles::NumActiveParticle, TreeWalk::postprocess, TreeWalk::priv, TreeWalk::query_type_elsize, TreeWalk::reduce, TreeWalk::repeatdisallowed, TreeWalk::result_type_elsize, slot_info::size, SlotsManager, MetalReturnPriv::spin, MetalReturnPriv::StarVolumeSPH, stellar_density(), TreeWalk::tree, treewalk_run(), treewalk_visit_ngbiter(), TreeWalk::visit, and walltime_measure.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metal_return_copy()

static void metal_return_copy ( int  place,
TreeWalkQueryMetals input,
TreeWalk tw 
)
static

Definition at line 583 of file metal_return.c.

584 {
585  input->Metallicity = STARP(place).Metallicity;
586  input->Mass = P[place].Mass;
587  input->Hsml = P[place].Hsml;
588  int pi = P[place].PI;
589  input->StarVolumeSPH = METALS_GET_PRIV(tw)->StarVolumeSPH[pi];
590  double InitialMass = P[place].Mass + STARP(place).TotalMassReturned;
591  double dtmyrend = METALS_GET_PRIV(tw)->StellarAges[pi];
592  double dtmyrstart = STARP(place).LastEnrichmentMyr;
593  int tid = omp_get_thread_num();
594  /* This is the total mass returned from this stellar population this timestep. Note this is already in the desired units.*/
595  input->MassGenerated = METALS_GET_PRIV(tw)->MassReturn[pi];
596  /* This returns the total amount of metal produced this timestep, and also fills out MetalSpeciesGenerated, which is an
597  * element by element table of the metal produced by dying stars this timestep.*/
598  double total_z_yield = metal_yield(dtmyrstart, dtmyrend, input->Metallicity, METALS_GET_PRIV(tw)->hub, &METALS_GET_PRIV(tw)->interp, input->MetalSpeciesGenerated, METALS_GET_PRIV(tw)->imf_norm, METALS_GET_PRIV(tw)->gsl_work[tid], METALS_GET_PRIV(tw)->LowDyingMass[pi], METALS_GET_PRIV(tw)->HighDyingMass[pi]);
599  /* The total metal returned is the metal created this timestep, plus the metal which was already in the mass returned by the dying stars.*/
600  input->MetalGenerated = InitialMass * total_z_yield + STARP(place).Metallicity * input->MassGenerated;
601  //message(3, "Particle %d PI %d z %g massgen %g metallicity %g\n", pi, P[pi].PI, total_z_yield, METALS_GET_PRIV(tw)->MassReturn[pi], STARP(place).Metallicity);
602  /* It should be positive! If it is not, this is some integration error
603  * in the yield table as we cannot destroy metal which is not present.*/
604  if(input->MetalGenerated < 0)
605  input->MetalGenerated = 0;
606  /* Similarly for all the other metal species*/
607  int i;
608  for(i = 0; i < NMETALS; i++) {
609  input->MetalSpeciesGenerated[i] = InitialMass * input->MetalSpeciesGenerated[i] + STARP(place).Metals[i] * input->MassGenerated;
610  if(input->MetalSpeciesGenerated[i] < 0)
611  input->MetalSpeciesGenerated[i] = 0;
612  }
613 }
#define METALS_GET_PRIV(tw)
Definition: metal_return.c:99
static double metal_yield(double dtmyrstart, double dtmyrend, double stellarmetal, double hub, struct interps *interp, MyFloat *MetalYields, double imf_norm, gsl_integration_workspace *gsl_work, double masslow, double masshigh)
Definition: metal_return.c:411
#define STARP(i)
Definition: slotsmanager.h:126
#define NMETALS
Definition: slotsmanager.h:60
MyFloat MetalSpeciesGenerated[NMETALS]
Definition: metal_return.c:108

References MetalReturnPriv::gsl_work, MetalReturnPriv::HighDyingMass, TreeWalkQueryMetals::Hsml, MetalReturnPriv::hub, MetalReturnPriv::imf_norm, interp, MetalReturnPriv::LowDyingMass, TreeWalkQueryMetals::Mass, TreeWalkQueryMetals::MassGenerated, metal_yield(), TreeWalkQueryMetals::MetalGenerated, TreeWalkQueryMetals::Metallicity, METALS_GET_PRIV, TreeWalkQueryMetals::MetalSpeciesGenerated, NMETALS, P, STARP, and TreeWalkQueryMetals::StarVolumeSPH.

Referenced by metal_return().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metal_return_haswork()

static int metal_return_haswork ( int  n,
TreeWalk tw 
)
static

Definition at line 720 of file metal_return.c.

721 {
722  return metals_haswork(i, METALS_GET_PRIV(tw)->MassReturn);
723 }
int metals_haswork(int i, MyFloat *MassReturn)
Definition: metal_return.c:708

References MetalReturnPriv::MassReturn, METALS_GET_PRIV, and metals_haswork().

Referenced by metal_return().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metal_return_init()

int64_t metal_return_init ( const ActiveParticles act,
Cosmology CP,
struct MetalReturnPriv priv,
const double  atime 
)

Definition at line 437 of file metal_return.c.

438 {
439  int nthread = omp_get_max_threads();
440  priv->gsl_work = ta_malloc("gsl_work", gsl_integration_workspace *, nthread);
441  int i;
442  /* Allocate a workspace for each thread*/
443  for(i=0; i < nthread; i++)
444  priv->gsl_work[i] = gsl_integration_workspace_alloc(GSL_WORKSPACE);
445  priv->hub = CP->HubbleParam;
446 
447  /* Initialize*/
449  priv->StellarAges = (MyFloat *) mymalloc("StellarAges", SlotsManager->info[4].size * sizeof(MyFloat));
450  priv->MassReturn = (MyFloat *) mymalloc("MassReturn", SlotsManager->info[4].size * sizeof(MyFloat));
451  priv->LowDyingMass = (MyFloat *) mymalloc("LowDyingMass", SlotsManager->info[4].size * sizeof(MyFloat));
452  priv->HighDyingMass = (MyFloat *) mymalloc("HighDyingMass", SlotsManager->info[4].size * sizeof(MyFloat));
453  priv->StarVolumeSPH = (MyFloat *) mymalloc("StarVolumeSPH", SlotsManager->info[4].size * sizeof(MyFloat));
454 
455  priv->imf_norm = compute_imf_norm(priv->gsl_work[0]);
456  /* Maximum possible mass return for below*/
457  double maxmassfrac = mass_yield(0, 1/(CP->HubbleParam*HUBBLE * SEC_PER_MEGAYEAR), snii_metallicities[SNII_NMET-1], CP->HubbleParam, &priv->interp, priv->imf_norm, priv->gsl_work[0],agb_masses[0], MAXMASS);
458 
459  int64_t haswork = 0;
460  /* First find the mass return as a fraction of the total mass and the age of the star.
461  * This is done first so we can skip density computation for not active stars*/
462  #pragma omp parallel for reduction(+: haswork)
463  for(i=0; i < act->NumActiveParticle;i++)
464  {
465  int p_i = act->ActiveParticle ? act->ActiveParticle[i] : i;
466  if(P[p_i].Type != 4)
467  continue;
468  int tid = omp_get_thread_num();
469  const int slot = P[p_i].PI;
470  priv->StellarAges[slot] = atime_to_myr(CP, STARP(p_i).FormationTime, atime, priv->gsl_work[tid]);
471  /* Note this takes care of units*/
472  double initialmass = P[p_i].Mass + STARP(p_i).TotalMassReturned;
473  find_mass_bin_limits(&priv->LowDyingMass[slot], &priv->HighDyingMass[slot], STARP(p_i).LastEnrichmentMyr, priv->StellarAges[P[p_i].PI], STARP(p_i).Metallicity, priv->interp.lifetime_interp);
474 
475  priv->MassReturn[slot] = initialmass * mass_yield(STARP(p_i).LastEnrichmentMyr, priv->StellarAges[P[p_i].PI], STARP(p_i).Metallicity, CP->HubbleParam, &priv->interp, priv->imf_norm, priv->gsl_work[tid],priv->LowDyingMass[slot], priv->HighDyingMass[slot]);
476  //message(3, "Particle %d PI %d massgen %g mass %g initmass %g\n", p_i, P[p_i].PI, priv->MassReturn[P[p_i].PI], P[p_i].Mass, initialmass);
477  /* Guard against making a zero mass particle and warn since this should not happen.*/
478  if(STARP(p_i).TotalMassReturned + priv->MassReturn[slot] > initialmass * maxmassfrac) {
479  if(priv->MassReturn[slot] / STARP(p_i).TotalMassReturned > 0.01)
480  message(1, "Large mass return id %ld %g from %d mass %g initial %g (maxfrac %g) age %g lastenrich %g metal %g dymass %g %g\n",
481  P[p_i].ID, priv->MassReturn[slot], p_i, STARP(p_i).TotalMassReturned, initialmass, maxmassfrac, priv->StellarAges[P[p_i].PI], STARP(p_i).LastEnrichmentMyr, STARP(p_i).Metallicity, priv->LowDyingMass[slot], priv->HighDyingMass[slot]);
482  priv->MassReturn[slot] = initialmass * maxmassfrac - STARP(p_i).TotalMassReturned;
483  if(priv->MassReturn[slot] < 0) {
484  priv->MassReturn[slot] = 0;
485  }
486  /* Ensure that we skip this step*/
487  if(!metals_haswork(p_i, priv->MassReturn))
488  STARP(p_i).LastEnrichmentMyr = priv->StellarAges[P[p_i].PI];
489 
490  }
491  /* Keep count of how much work we need to do*/
492  if(metals_haswork(p_i, priv->MassReturn))
493  haswork++;
494  }
495  return haswork;
496 }
void message(int where, const char *fmt,...)
Definition: endrun.c:175
static double mass_yield(double dtmyrstart, double dtmyrend, double stellarmetal, double hub, struct interps *interp, double imf_norm, gsl_integration_workspace *gsl_work, double masslow, double masshigh)
Definition: metal_return.c:395
void find_mass_bin_limits(double *masslow, double *masshigh, const double dtstart, const double dtend, double stellarmetal, gsl_interp2d *lifetime_tables)
Definition: metal_return.c:230
void setup_metal_table_interp(struct interps *interp)
Definition: metal_return.c:76
double compute_imf_norm(gsl_integration_workspace *gsl_work)
Definition: metal_return.c:314
static double atime_to_myr(Cosmology *CP, double atime1, double atime2, gsl_integration_workspace *gsl_work)
Definition: metal_return.c:161
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define ta_malloc(name, type, nele)
Definition: mymalloc.h:25
#define HUBBLE
Definition: physconst.h:25
double HubbleParam
Definition: cosmology.h:20
gsl_integration_workspace ** gsl_work
Definition: metal_return.h:27
MyFloat * StarVolumeSPH
Definition: metal_return.h:37
MyFloat * HighDyingMass
Definition: metal_return.h:31
MyFloat * StellarAges
Definition: metal_return.h:28
struct interps interp
Definition: metal_return.h:38
MyFloat * MassReturn
Definition: metal_return.h:29
MyFloat * LowDyingMass
Definition: metal_return.h:30
gsl_interp2d * lifetime_interp
Definition: metal_return.h:13
LOW_PRECISION MyFloat
Definition: types.h:19

References ActiveParticles::ActiveParticle, agb_masses, atime_to_myr(), compute_imf_norm(), CP, find_mass_bin_limits(), MetalReturnPriv::gsl_work, GSL_WORKSPACE, MetalReturnPriv::HighDyingMass, MetalReturnPriv::hub, HUBBLE, Cosmology::HubbleParam, MetalReturnPriv::imf_norm, slots_manager_type::info, MetalReturnPriv::interp, interps::lifetime_interp, MetalReturnPriv::LowDyingMass, mass_yield(), MetalReturnPriv::MassReturn, MAXMASS, message(), metals_haswork(), mymalloc, ActiveParticles::NumActiveParticle, P, SEC_PER_MEGAYEAR, setup_metal_table_interp(), slot_info::size, SlotsManager, snii_metallicities, SNII_NMET, STARP, MetalReturnPriv::StarVolumeSPH, MetalReturnPriv::StellarAges, and ta_malloc.

Referenced by metal_return().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metal_return_ngbiter()

static void metal_return_ngbiter ( TreeWalkQueryMetals I,
TreeWalkResultMetals O,
TreeWalkNgbIterMetals iter,
LocalTreeWalk lv 
)
static

For all gas particles within the density radius of this star, add a fraction of the total mass and metals generated, weighted by the SPH kernel distance from the star.

Definition at line 633 of file metal_return.c.

639 {
640  if(iter->base.other == -1) {
641  /* Only return metals to gas*/
642  iter->base.mask = 1;
643  iter->base.Hsml = I->Hsml;
645  /* Initialise the mass lost by this star in this timestep*/
646  O->MassReturn = 0;
648  return;
649  }
650 
651  const int other = iter->base.other;
652  const double r2 = iter->base.r2;
653  const double r = iter->base.r;
654 
655  if(r2 > 0 && r2 < iter->kernel.HH)
656  {
657  double wk = 1;
658  const double u = r * iter->kernel.Hinv;
659 
661  wk = density_kernel_wk(&iter->kernel, u);
662  double ThisMetals[NMETALS];
663  if(I->StarVolumeSPH ==0)
664  endrun(3, "StarVolumeSPH %g hsml %g\n", I->StarVolumeSPH, I->Hsml);
665  double newmass;
666  int pi = P[other].PI;
667  lock_spinlock(pi, METALS_GET_PRIV(lv->tw)->spin);
668  /* Volume of particle weighted by the SPH kernel*/
669  double volume = P[other].Mass / SPHP(other).Density;
670  double returnfraction = wk * volume / I->StarVolumeSPH;
671  int i;
672  for(i = 0; i < NMETALS; i++)
673  ThisMetals[i] = returnfraction * I->MetalSpeciesGenerated[i];
674  /* Keep track of how much was returned for conservation purposes*/
675  double thismass = returnfraction * I->MassGenerated;
676  O->MassReturn += thismass;
677  /* Add metals weighted by SPH kernel*/
678  double thismetal = returnfraction * I->MetalGenerated;
679  /* Add the metals to the particle.*/
680  for(i = 0; i < NMETALS; i++)
681  SPHP(other).Metals[i] = (SPHP(other).Metals[i] * P[other].Mass + ThisMetals[i])/(P[other].Mass + thismass);
682  /* Update total metallicity*/
683  SPHP(other).Metallicity = (SPHP(other).Metallicity * P[other].Mass + thismetal)/(P[other].Mass + thismass);
684  /* Update mass*/
685  double massfrac = (P[other].Mass + thismass) / P[other].Mass;
686  /* Ensure that the gas particles don't become overweight.
687  * If there are few gas particles around, the star clusters
688  * will hold onto their metals.*/
689  if(P[other].Mass + thismass < METALS_GET_PRIV(lv->tw)->MaxGasMass) {
690  P[other].Mass *= massfrac;
691  /* Density also needs a correction so the volume fraction is unchanged.
692  * This ensures that volume = Mass/Density is unchanged for the next particle
693  * and thus the weighting still sums to unity.*/
694  SPHP(other).Density *= massfrac;
695  }
696  newmass = P[other].Mass;
697  unlock_spinlock(pi, METALS_GET_PRIV(lv->tw)->spin);
698  if(newmass <= 0)
699  endrun(3, "New mass %g new metal %g in particle %d id %ld from star mass %g metallicity %g\n",
700  newmass, SPHP(other).Metallicity, other, P[other].ID, I->Mass, I->Metallicity);
701  }
702 }
enum DensityKernelType GetDensityKernelType(void)
Definition: density.c:63
double(* wk)(DensityKernel *kernel, double q)
Definition: densitykernel.c:94
void density_kernel_init(DensityKernel *kernel, double H, enum DensityKernelType type)
double density_kernel_wk(DensityKernel *kernel, double u)
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
static double kernel(double loga, void *params)
Definition: lightcone.c:59
static struct metal_return_params MetalParams
#define SPHP(i)
Definition: slotsmanager.h:124
void lock_spinlock(int i, struct SpinLocks *spin)
Definition: spinlocks.c:23
void unlock_spinlock(int i, struct SpinLocks *spin)
Definition: spinlocks.c:30
TreeWalk * tw
Definition: treewalk.h:47
enum NgbTreeFindSymmetric symmetric
Definition: treewalk.h:37
TreeWalkNgbIterBase base
Definition: metal_return.c:121
DensityKernel kernel
Definition: metal_return.c:122
@ NGB_TREEFIND_ASYMMETRIC
Definition: treewalk.h:12

References TreeWalkNgbIterMetals::base, density_kernel_init(), density_kernel_wk(), endrun(), GetDensityKernelType(), DensityKernel::Hinv, TreeWalkQueryMetals::Hsml, TreeWalkNgbIterBase::Hsml, kernel(), TreeWalkNgbIterMetals::kernel, lock_spinlock(), TreeWalkNgbIterBase::mask, TreeWalkQueryMetals::Mass, TreeWalkQueryMetals::MassGenerated, TreeWalkResultMetals::MassReturn, TreeWalkQueryMetals::MetalGenerated, TreeWalkQueryMetals::Metallicity, MetalParams, METALS_GET_PRIV, TreeWalkQueryMetals::MetalSpeciesGenerated, NGB_TREEFIND_ASYMMETRIC, NMETALS, TreeWalkNgbIterBase::other, P, TreeWalkNgbIterBase::r, TreeWalkNgbIterBase::r2, SPHP, metal_return_params::SPHWeighting, TreeWalkQueryMetals::StarVolumeSPH, TreeWalkNgbIterBase::symmetric, LocalTreeWalk::tw, unlock_spinlock(), and wk.

Referenced by metal_return().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metal_return_postprocess()

static void metal_return_postprocess ( int  place,
TreeWalk tw 
)
static

Definition at line 619 of file metal_return.c.

620 {
621  /* Conserve mass returned*/
622  P[place].Mass -= METALS_GET_PRIV(tw)->MassReturn[P[place].PI];
623  STARP(place).TotalMassReturned += METALS_GET_PRIV(tw)->MassReturn[P[place].PI];
624  /* Update the last enrichment time*/
625  STARP(place).LastEnrichmentMyr = METALS_GET_PRIV(tw)->StellarAges[P[place].PI];
626 }

References METALS_GET_PRIV, P, and STARP.

Referenced by metal_return().

Here is the caller graph for this function:

◆ metal_return_priv_free()

void metal_return_priv_free ( struct MetalReturnPriv priv)

Definition at line 500 of file metal_return.c.

501 {
502  myfree(priv->StarVolumeSPH);
503  myfree(priv->HighDyingMass);
504  myfree(priv->LowDyingMass);
505  myfree(priv->MassReturn);
506  myfree(priv->StellarAges);
507 
508  int i;
509  for(i=0; i < omp_get_max_threads(); i++)
510  gsl_integration_workspace_free(priv->gsl_work[i]);
511 
512  ta_free(priv->gsl_work);
513 }
#define ta_free(p)
Definition: mymalloc.h:28
#define myfree(x)
Definition: mymalloc.h:19

References MetalReturnPriv::gsl_work, MetalReturnPriv::HighDyingMass, MetalReturnPriv::LowDyingMass, MetalReturnPriv::MassReturn, myfree, MetalReturnPriv::StarVolumeSPH, MetalReturnPriv::StellarAges, and ta_free.

Referenced by metal_return().

Here is the caller graph for this function:

◆ metal_yield()

static double metal_yield ( double  dtmyrstart,
double  dtmyrend,
double  stellarmetal,
double  hub,
struct interps interp,
MyFloat MetalYields,
double  imf_norm,
gsl_integration_workspace *  gsl_work,
double  masslow,
double  masshigh 
)
static

Definition at line 411 of file metal_return.c.

412 {
413  double MetalGenerated = 0;
414  /* Number of AGB stars/SnII by integrating the IMF*/
415  MetalGenerated += compute_agb_yield(interp->agb_metallicity_interp, agb_total_metals, stellarmetal, masslow, masshigh, gsl_work);
416  MetalGenerated += compute_snii_yield(interp->snii_metallicity_interp, snii_total_metals, stellarmetal, masslow, masshigh, gsl_work);
417  MetalGenerated /= imf_norm;
418 
419  int i;
420  for(i = 0; i < NMETALS; i++)
421  {
422  MetalYields[i] = 0;
423  MetalYields[i] += compute_agb_yield(interp->agb_metals_interp[i], agb_yield[i], stellarmetal, masslow, masshigh, gsl_work);
424  MetalYields[i] += compute_snii_yield(interp->snii_metals_interp[i], snii_yield[i], stellarmetal, masslow, masshigh, gsl_work);
425  MetalYields[i] /= imf_norm;
426  }
427  double Nsn1a = sn1a_number(dtmyrstart, dtmyrend, hub);
428  for(i = 0; i < NMETALS; i++)
429  MetalYields[i] += Nsn1a * sn1a_yields[i];
430  MetalGenerated += Nsn1a * sn1a_total_metals;
431 
432  return MetalGenerated;
433 }
static const double snii_yield[NSPECIES][SNII_NMET *SNII_NMASS]
Definition: metal_tables.h:334
static const double sn1a_yields[NSPECIES]
Definition: metal_tables.h:61
static const double agb_total_metals[AGB_NMET *AGB_NMASS]
Definition: metal_tables.h:94
static const double agb_yield[NSPECIES][AGB_NMET *AGB_NMASS]
Definition: metal_tables.h:116
static const double snii_total_metals[SNII_NMET *SNII_NMASS]
Definition: metal_tables.h:323

References agb_total_metals, agb_yield, compute_agb_yield(), compute_snii_yield(), interp, NMETALS, sn1a_number(), sn1a_total_metals, sn1a_yields, snii_total_metals, and snii_yield.

Referenced by metal_return_copy().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ metals_haswork()

int metals_haswork ( int  i,
MyFloat MassReturn 
)

Definition at line 708 of file metal_return.c.

709 {
710  if(P[i].Type != 4)
711  return 0;
712  int pi = P[i].PI;
713  /* Don't do enrichment from all stars, just those with significant enrichment*/
714  if(MassReturn[pi] < 1e-3 * (P[i].Mass + STARP(i).TotalMassReturned))
715  return 0;
716  return 1;
717 }

References MetalReturnPriv::MassReturn, P, and STARP.

Referenced by metal_return_haswork(), metal_return_init(), and stellar_density_haswork().

Here is the caller graph for this function:

◆ set_metal_params()

void set_metal_params ( double  Sn1aN0)

Definition at line 55 of file metal_return.c.

56 {
57  MetalParams.Sn1aN0 = Sn1aN0;
58 }

References MetalParams, and metal_return_params::Sn1aN0.

Referenced by test_yields().

Here is the caller graph for this function:

◆ set_metal_return_params()

void set_metal_return_params ( ParameterSet ps)

Definition at line 62 of file metal_return.c.

63 {
64  int ThisTask;
65  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
66  if(ThisTask == 0) {
67  MetalParams.Sn1aN0 = param_get_double(ps, "MetalsSn1aN0");
68  MetalParams.SPHWeighting = param_get_int(ps, "MetalsSPHWeighting");
69  MetalParams.MaxNgbDeviation = param_get_double(ps, "MetalsMaxNgbDeviation");
70  }
71  MPI_Bcast(&MetalParams, sizeof(struct metal_return_params), MPI_BYTE, 0, MPI_COMM_WORLD);
72 }
double param_get_double(ParameterSet *ps, const char *name)
Definition: paramset.c:336
int param_get_int(ParameterSet *ps, const char *name)
Definition: paramset.c:368
int ThisTask
Definition: test_exchange.c:23

References metal_return_params::MaxNgbDeviation, MetalParams, param_get_double(), param_get_int(), metal_return_params::Sn1aN0, metal_return_params::SPHWeighting, and ThisTask.

Referenced by read_parameter_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_metal_table_interp()

void setup_metal_table_interp ( struct interps interp)

Definition at line 76 of file metal_return.c.

77 {
78  interp->lifetime_interp = gsl_interp2d_alloc(gsl_interp2d_bilinear, LIFE_NMET, LIFE_NMASS);
79  gsl_interp2d_init(interp->lifetime_interp, lifetime_metallicity, lifetime_masses, lifetime, LIFE_NMET, LIFE_NMASS);
80  interp->agb_mass_interp = gsl_interp2d_alloc(gsl_interp2d_bilinear, AGB_NMET, AGB_NMASS);
81  gsl_interp2d_init(interp->agb_mass_interp, agb_metallicities, agb_masses, agb_total_mass, AGB_NMET, AGB_NMASS);
82  interp->agb_metallicity_interp = gsl_interp2d_alloc(gsl_interp2d_bilinear, AGB_NMET, AGB_NMASS);
83  gsl_interp2d_init(interp->agb_metallicity_interp, agb_metallicities, agb_masses, agb_total_metals, AGB_NMET, AGB_NMASS);
84  int i;
85  for(i=0; i<NMETALS; i++) {
86  interp->agb_metals_interp[i] = gsl_interp2d_alloc(gsl_interp2d_bilinear, AGB_NMET, AGB_NMASS);
87  gsl_interp2d_init(interp->agb_metals_interp[i], agb_metallicities, agb_masses, agb_yield[i], AGB_NMET, AGB_NMASS);
88  }
89  interp->snii_mass_interp = gsl_interp2d_alloc(gsl_interp2d_bilinear, SNII_NMET, SNII_NMASS);
90  gsl_interp2d_init(interp->snii_mass_interp, snii_metallicities, snii_masses, snii_total_mass, SNII_NMET, SNII_NMASS);
91  interp->snii_metallicity_interp = gsl_interp2d_alloc(gsl_interp2d_bilinear, SNII_NMET, SNII_NMASS);
92  gsl_interp2d_init(interp->snii_metallicity_interp, snii_metallicities, snii_masses, snii_total_metals, SNII_NMET, SNII_NMASS);
93  for(i=0; i<NMETALS; i++) {
94  interp->snii_metals_interp[i] = gsl_interp2d_alloc(gsl_interp2d_bilinear, SNII_NMET, SNII_NMASS);
95  gsl_interp2d_init(interp->snii_metals_interp[i], snii_metallicities, snii_masses, snii_yield[i], SNII_NMET, SNII_NMASS);
96  }
97 }
#define LIFE_NMASS
Definition: metal_tables.h:17
#define AGB_NMASS
Definition: metal_tables.h:69

References agb_masses, agb_metallicities, AGB_NMASS, AGB_NMET, agb_total_mass, agb_total_metals, agb_yield, interp, LIFE_NMASS, LIFE_NMET, lifetime, lifetime_masses, lifetime_metallicity, NMETALS, snii_masses, snii_metallicities, SNII_NMASS, SNII_NMET, snii_total_mass, snii_total_metals, and snii_yield.

Referenced by metal_return_init(), and test_yields().

Here is the caller graph for this function:

◆ sn1a_number()

double sn1a_number ( double  dtmyrstart,
double  dtmyrend,
double  hub 
)

Definition at line 324 of file metal_return.c.

325 {
326  /* Number of Sn1a events follows a delay time distribution (1305.2913, eq. 10) */
327  const double sn1aindex = 1.12;
328  const double tau8msun = 40;
329  if(dtmyrend < tau8msun)
330  return 0;
331  /* Lower integration limit modelling formation time of WDs*/
332  if(dtmyrstart < tau8msun)
333  dtmyrstart = tau8msun;
334  /* Total number of Sn1a events from this star: integral evaluated from t=tau8msun to t=hubble time.*/
335  const double totalSN1a = 1- pow(1/(hub*HUBBLE * SEC_PER_MEGAYEAR)/tau8msun, 1-sn1aindex);
336  /* This is the integral of the DTD, normalised to the N0 rate which is in SN/M_sun.*/
337  double Nsn1a = MetalParams.Sn1aN0 /totalSN1a * (pow(dtmyrstart / tau8msun, 1-sn1aindex) - pow(dtmyrend / tau8msun, 1-sn1aindex));
338  return Nsn1a;
339 }

References HUBBLE, MetalParams, SEC_PER_MEGAYEAR, and metal_return_params::Sn1aN0.

Referenced by mass_yield(), metal_yield(), and test_yields().

Here is the caller graph for this function:

◆ stellar_density()

void stellar_density ( const ActiveParticles act,
MyFloat StarVolumeSPH,
MyFloat MassReturn,
const ForceTree *const  tree 
)

Definition at line 923 of file metal_return.c.

924 {
925  TreeWalk tw[1] = {{0}};
926  struct StellarDensityPriv priv[1];
927 
928  tw->ev_label = "STELLAR_DENSITY";
930  tw->NoNgblist = 1;
939  tw->priv = priv;
940  tw->tree = tree;
941 
942  int i;
943 
944  priv->MassReturn = MassReturn;
945 
946  priv->Left = (MyFloat *) mymalloc("DENS_PRIV->Left", SlotsManager->info[4].size * sizeof(MyFloat));
947  priv->Right = (MyFloat *) mymalloc("DENS_PRIV->Right", SlotsManager->info[4].size * sizeof(MyFloat));
948  priv->NumNgb = (MyFloat (*) [NHSML]) mymalloc("DENS_PRIV->NumNgb", SlotsManager->info[4].size * sizeof(priv->NumNgb[0]));
949  priv->VolumeSPH = (MyFloat (*) [NHSML]) mymalloc("DENS_PRIV->VolumeSPH", SlotsManager->info[4].size * sizeof(priv->VolumeSPH[0]));
950  priv->maxcmpte = (int *) mymalloc("maxcmpte", SlotsManager->info[4].size * sizeof(int));
951 
952  priv->DesNumNgb = GetNumNgb(GetDensityKernelType());
953 
954  #pragma omp parallel for
955  for(i = 0; i < act->NumActiveParticle; i++) {
956  int a = act->ActiveParticle ? act->ActiveParticle[i] : i;
957  /* Skip the garbage particles */
958  if(P[a].IsGarbage)
959  continue;
960  if(!stellar_density_haswork(a, tw))
961  continue;
962  int pi = P[a].PI;
963  priv->Left[pi] = 0;
964  priv->Right[pi] = tree->BoxSize;
965  }
966 
967  /* allocate buffers to arrange communication */
968 
970  #pragma omp parallel for
971  for(i = 0; i < act->NumActiveParticle; i++) {
972  int a = act->ActiveParticle ? act->ActiveParticle[i] : i;
973  /* Skip the garbage particles */
974  if(P[a].IsGarbage)
975  continue;
976  if(!stellar_density_haswork(a, tw))
977  continue;
978  /* Copy the Star Volume SPH*/
979  StarVolumeSPH[P[a].PI] = priv->VolumeSPH[P[a].PI][0];
980  if(priv->VolumeSPH[P[a].PI][0] == 0)
981  endrun(3, "i = %d pi = %d StarVolumeSPH %g hsml %g\n", a, P[a].PI, priv->VolumeSPH[P[a].PI][0], P[a].Hsml);
982  }
983 
984  myfree(priv->maxcmpte);
985  myfree(priv->VolumeSPH);
986  myfree(priv->NumNgb);
987  myfree(priv->Right);
988  myfree(priv->Left);
989 
990  double timeall = walltime_measure(WALLTIME_IGNORE);
991 
992  double timecomp = tw->timecomp3 + tw->timecomp1 + tw->timecomp2;
993  double timewait = tw->timewait1 + tw->timewait2;
994  double timecomm = tw->timecommsumm1 + tw->timecommsumm2;
995  walltime_add("/SPH/Metals/Density/Compute", timecomp);
996  walltime_add("/SPH/Metals/Density/Wait", timewait);
997  walltime_add("/SPH/Metals/Density/Comm", timecomm);
998  walltime_add("/SPH/Metals/Density/Misc", timeall - (timecomp + timewait + timecomm));
999 
1000  return;
1001 }
double GetNumNgb(enum DensityKernelType KernelType)
Definition: density.c:55
void stellar_density_check_neighbours(int i, TreeWalk *tw)
Definition: metal_return.c:820
static void stellar_density_reduce(int place, TreeWalkResultStellarDensity *remote, enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: metal_return.c:808
static int stellar_density_haswork(int i, TreeWalk *tw)
Definition: metal_return.c:765
static void stellar_density_ngbiter(TreeWalkQueryStellarDensity *I, TreeWalkResultStellarDensity *O, TreeWalkNgbIterStellarDensity *iter, LocalTreeWalk *lv)
Definition: metal_return.c:872
static void stellar_density_copy(int place, TreeWalkQueryStellarDensity *I, TreeWalk *tw)
Definition: metal_return.c:800
MyFloat * MassReturn
Definition: metal_return.c:755
double timecomp2
Definition: treewalk.h:124
double timecomp3
Definition: treewalk.h:125
double timecommsumm1
Definition: treewalk.h:126
double timewait2
Definition: treewalk.h:122
int NoNgblist
Definition: treewalk.h:156
double timecomp1
Definition: treewalk.h:123
double timewait1
Definition: treewalk.h:121
double timecommsumm2
Definition: treewalk.h:127
int treewalk_visit_nolist_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
Definition: treewalk.c:1143
void treewalk_do_hsml_loop(TreeWalk *tw, int *queue, int64_t queuesize, int update_hsml)
Definition: treewalk.c:1254
void(* TreeWalkReduceResultFunction)(const int j, TreeWalkResultBase *result, const enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: treewalk.h:76
#define WALLTIME_IGNORE
Definition: walltime.h:6
#define walltime_add(name, dt)
Definition: walltime.h:9

References ActiveParticles::ActiveParticle, ForceTree::BoxSize, StellarDensityPriv::DesNumNgb, endrun(), TreeWalk::ev_label, TreeWalk::fill, GetDensityKernelType(), GetNumNgb(), TreeWalk::haswork, slots_manager_type::info, StellarDensityPriv::Left, StellarDensityPriv::MassReturn, StellarDensityPriv::maxcmpte, myfree, mymalloc, TreeWalk::ngbiter, TreeWalk::ngbiter_type_elsize, NHSML, TreeWalk::NoNgblist, ActiveParticles::NumActiveParticle, StellarDensityPriv::NumNgb, P, TreeWalk::postprocess, TreeWalk::priv, TreeWalk::query_type_elsize, TreeWalk::reduce, TreeWalk::result_type_elsize, StellarDensityPriv::Right, slot_info::size, SlotsManager, stellar_density_check_neighbours(), stellar_density_copy(), stellar_density_haswork(), stellar_density_ngbiter(), stellar_density_reduce(), TreeWalk::timecommsumm1, TreeWalk::timecommsumm2, TreeWalk::timecomp1, TreeWalk::timecomp2, TreeWalk::timecomp3, TreeWalk::timewait1, TreeWalk::timewait2, TreeWalk::tree, treewalk_do_hsml_loop(), treewalk_visit_nolist_ngbiter(), TreeWalk::visit, StellarDensityPriv::VolumeSPH, walltime_add, WALLTIME_IGNORE, and walltime_measure.

Referenced by metal_return().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stellar_density_check_neighbours()

void stellar_density_check_neighbours ( int  i,
TreeWalk tw 
)

Definition at line 820 of file metal_return.c.

821 {
822  MyFloat * Left = STELLAR_DENSITY_GET_PRIV(tw)->Left;
823  MyFloat * Right = STELLAR_DENSITY_GET_PRIV(tw)->Right;
824 
825  int pi = P[i].PI;
826  int tid = omp_get_thread_num();
827  double desnumngb = STELLAR_DENSITY_GET_PRIV(tw)->DesNumNgb;
828 
829  const int maxcmpt = STELLAR_DENSITY_GET_PRIV(tw)->maxcmpte[pi];
830  int j;
831  double evalhsml[NHSML];
832  for(j = 0; j < maxcmpt; j++)
833  evalhsml[j] = effhsml(i, j, tw);
834 
835  int close = 0;
836  P[i].Hsml = ngb_narrow_down(&Right[pi],&Left[pi],evalhsml,STELLAR_DENSITY_GET_PRIV(tw)->NumNgb[pi],maxcmpt,desnumngb,&close,tw->tree->BoxSize);
837  double numngb = STELLAR_DENSITY_GET_PRIV(tw)->NumNgb[pi][close];
838 
839  /* Save VolumeSPH*/
840  STELLAR_DENSITY_GET_PRIV(tw)->VolumeSPH[pi][0] = STELLAR_DENSITY_GET_PRIV(tw)->VolumeSPH[pi][close];
841 
842  /* now check whether we had enough neighbours */
843  if(numngb < (desnumngb - MetalParams.MaxNgbDeviation) ||
844  (numngb > (desnumngb + MetalParams.MaxNgbDeviation)))
845  {
846  /* This condition is here to prevent the density code looping forever if it encounters
847  * multiple particles at the same position. If this happens you likely have worse
848  * problems anyway, so warn also. */
849  if((Right[pi] - Left[pi]) < 1.0e-4 * Left[pi])
850  {
851  /* If this happens probably the exchange is screwed up and all your particles have moved to (0,0,0)*/
852  message(1, "Very tight Hsml bounds for i=%d ID=%lu type %d Hsml=%g Left=%g Right=%g Ngbs=%g des = %g Right-Left=%g pos=(%g|%g|%g)\n",
853  i, P[i].ID, P[i].Type, effhsml, Left[pi], Right[pi], numngb, desnumngb, Right[pi] - Left[pi], P[i].Pos[0], P[i].Pos[1], P[i].Pos[2]);
854  return;
855  }
856  /* More work needed: add this particle to the redo queue*/
857  tw->NPRedo[tid][tw->NPLeft[tid]] = i;
858  tw->NPLeft[tid] ++;
859  if(tw->Niteration >= 10)
860  message(1, "i=%d ID=%lu Hsml=%g lastdhsml=%g Left=%g Right=%g Ngbs=%g Right-Left=%g pos=(%g|%g|%g) fac = %g\n",
861  i, P[i].ID, P[i].Hsml, evalhsml[close], Left[pi], Right[pi], numngb, Right[pi] - Left[pi], P[i].Pos[0], P[i].Pos[1], P[i].Pos[2]);
862 
863  }
864  if(tw->maxnumngb[tid] < numngb)
865  tw->maxnumngb[tid] = numngb;
866  if(tw->minnumngb[tid] > numngb)
867  tw->minnumngb[tid] = numngb;
868 
869 }
static double effhsml(int place, int i, TreeWalk *tw)
Definition: metal_return.c:772
int64_t Niteration
Definition: treewalk.h:142
double * minnumngb
Definition: treewalk.h:172
double * maxnumngb
Definition: treewalk.h:171
int ** NPRedo
Definition: treewalk.h:168
size_t * NPLeft
Definition: treewalk.h:167
double ngb_narrow_down(double *right, double *left, const double *radius, const double *numNgb, int maxcmpt, int desnumngb, int *closeidx, double BoxSize)
Definition: treewalk.c:1366

References ForceTree::BoxSize, effhsml(), metal_return_params::MaxNgbDeviation, TreeWalk::maxnumngb, message(), MetalParams, TreeWalk::minnumngb, ngb_narrow_down(), NHSML, TreeWalk::Niteration, TreeWalk::NPLeft, TreeWalk::NPRedo, P, STELLAR_DENSITY_GET_PRIV, and TreeWalk::tree.

Referenced by stellar_density().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stellar_density_copy()

static void stellar_density_copy ( int  place,
TreeWalkQueryStellarDensity I,
TreeWalk tw 
)
static

Definition at line 800 of file metal_return.c.

801 {
802  int i;
803  for(i = 0; i < NHSML; i++)
804  I->Hsml[i] = effhsml(place, i, tw);
805 }

References effhsml(), TreeWalkQueryStellarDensity::Hsml, and NHSML.

Referenced by stellar_density().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stellar_density_haswork()

static int stellar_density_haswork ( int  i,
TreeWalk tw 
)
static

Definition at line 765 of file metal_return.c.

766 {
767  return metals_haswork(i, STELLAR_DENSITY_GET_PRIV(tw)->MassReturn);
768 }

References metals_haswork(), and STELLAR_DENSITY_GET_PRIV.

Referenced by stellar_density().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stellar_density_ngbiter()

static void stellar_density_ngbiter ( TreeWalkQueryStellarDensity I,
TreeWalkResultStellarDensity O,
TreeWalkNgbIterStellarDensity iter,
LocalTreeWalk lv 
)
static

Definition at line 872 of file metal_return.c.

877 {
878  if(iter->base.other == -1) {
879  int i;
880  for(i = 0; i < NHSML; i++) {
882  iter->kernel_volume[i] = density_kernel_volume(&iter->kernel[i]);
883  }
884  iter->base.Hsml = I->Hsml[NHSML-1];
885  iter->base.mask = 1; /* gas only */
887  O->maxcmpte = NHSML;
888  return;
889  }
890  const int other = iter->base.other;
891  const double r = iter->base.r;
892  const double r2 = iter->base.r2;
893 
894  int i;
895  for(i = 0; i < O->maxcmpte; i++) {
896  if(r2 < iter->kernel[i].HH)
897  {
898  const double u = r * iter->kernel[i].Hinv;
899  double wk = density_kernel_wk(&iter->kernel[i], u);
900  O->Ngb[i] += wk * iter->kernel_volume[i];
901  /* For stars we need the total weighting, sum(w_k m_k / rho_k).*/
902  double thisvol = P[other].Mass / SPHP(other).Density;
904  thisvol *= wk;
905  O->VolumeSPH[i] += thisvol;
906  }
907  }
908  double desnumngb = STELLAR_DENSITY_GET_PRIV(lv->tw)->DesNumNgb;
909  /* If there is an entry which is above desired DesNumNgb,
910  * we don't need to search past it. After this point
911  * all entries in the Ngb table above O->Ngb are invalid.*/
912  for(i = 0; i < NHSML; i++) {
913  if(O->Ngb[i] > desnumngb) {
914  O->maxcmpte = i+1;
915  iter->base.Hsml = I->Hsml[i];
916  break;
917  }
918  }
919 
920 }
double density_kernel_volume(DensityKernel *kernel)
DensityKernel kernel[NHSML]
Definition: metal_return.c:730
TreeWalkNgbIterBase base
Definition: metal_return.c:729

References TreeWalkNgbIterStellarDensity::base, density_kernel_init(), density_kernel_volume(), density_kernel_wk(), GetDensityKernelType(), DensityKernel::Hinv, TreeWalkQueryStellarDensity::Hsml, TreeWalkNgbIterBase::Hsml, kernel(), TreeWalkNgbIterStellarDensity::kernel, TreeWalkNgbIterStellarDensity::kernel_volume, TreeWalkNgbIterBase::mask, TreeWalkResultStellarDensity::maxcmpte, MetalParams, TreeWalkResultStellarDensity::Ngb, NGB_TREEFIND_ASYMMETRIC, NHSML, TreeWalkNgbIterBase::other, P, TreeWalkNgbIterBase::r, TreeWalkNgbIterBase::r2, SPHP, metal_return_params::SPHWeighting, STELLAR_DENSITY_GET_PRIV, TreeWalkNgbIterBase::symmetric, LocalTreeWalk::tw, TreeWalkResultStellarDensity::VolumeSPH, and wk.

Referenced by stellar_density().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stellar_density_reduce()

static void stellar_density_reduce ( int  place,
TreeWalkResultStellarDensity remote,
enum TreeWalkReduceMode  mode,
TreeWalk tw 
)
static

Definition at line 808 of file metal_return.c.

809 {
810  int pi = P[place].PI;
811  int i;
812  if(mode == 0 || STELLAR_DENSITY_GET_PRIV(tw)->maxcmpte[pi] > remote->maxcmpte)
813  STELLAR_DENSITY_GET_PRIV(tw)->maxcmpte[pi] = remote->maxcmpte;
814  for(i = 0; i < remote->maxcmpte; i++) {
815  TREEWALK_REDUCE(STELLAR_DENSITY_GET_PRIV(tw)->NumNgb[pi][i], remote->Ngb[i]);
816  TREEWALK_REDUCE(STELLAR_DENSITY_GET_PRIV(tw)->VolumeSPH[pi][i], remote->VolumeSPH[i]);
817  }
818 }
#define TREEWALK_REDUCE(A, B)
Definition: treewalk.h:189

References TreeWalkResultStellarDensity::maxcmpte, TreeWalkResultStellarDensity::Ngb, P, STELLAR_DENSITY_GET_PRIV, TREEWALK_REDUCE, and TreeWalkResultStellarDensity::VolumeSPH.

Referenced by stellar_density().

Here is the caller graph for this function:

Variable Documentation

◆ MetalParams

struct metal_return_params MetalParams
static