6 #include <gsl/gsl_math.h>
7 #include <gsl/gsl_integration.h>
8 #include <gsl/gsl_interp2d.h>
9 #include <gsl/gsl_roots.h>
10 #include <gsl/gsl_errno.h>
43 #if NMETALS != NSPECIES
44 #pragma error " Inconsistency in metal number between slots and metals"
65 MPI_Comm_rank(MPI_COMM_WORLD, &
ThisTask);
99 #define METALS_GET_PRIV(tw) ((struct MetalReturnPriv*) ((tw)->priv))
147 return 0.852464 / mass * exp(- pow(log(mass / 0.079)/ 0.69, 2)/2);
150 return 0.237912 * pow(mass, -2.3);
168 gsl_integration_qag(&ff, atime1, atime2, 1e-4, 0,
GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &tmyr, &abserr);
189 double tlifemyr = tlife/1e6;
190 return tlifemyr - p->
dtfind;
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);
208 for(iter = 0; iter <
MAXITER; iter++)
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,
216 if (status == GSL_SUCCESS)
219 double root = gsl_root_fsolver_root(s);
220 gsl_root_fsolver_free (s);
240 p.
metalacc = gsl_interp_accel_alloc();
241 p.
massacc = gsl_interp_accel_alloc();
268 *masshigh = *masslow;
272 gsl_interp_accel_free(p.
massacc);
295 double intpmass = mass;
296 if(mass < para->
masses[0])
297 intpmass = para->
masses[0];
303 weight *= (mass/intpmass);
324 double sn1a_number(
double dtmyrstart,
double dtmyrend,
double hub)
327 const double sn1aindex = 1.12;
328 const double tau8msun = 40;
329 if(dtmyrend < tau8msun)
332 if(dtmyrstart < tau8msun)
333 dtmyrstart = tau8msun;
337 double Nsn1a =
MetalParams.
Sn1aN0 /totalSN1a * (pow(dtmyrstart / tau8msun, 1-sn1aindex) - pow(dtmyrend / tau8msun, 1-sn1aindex));
342 double compute_agb_yield(gsl_interp2d * agb_interp,
const double * agb_weights,
double stellarmetal,
double masslow,
double masshigh, gsl_integration_workspace * gsl_work )
346 double agbyield = 0, abserr;
357 if(masslow >= masshigh)
364 gsl_integration_qag(&ff, masslow, masshigh, 1e-7, 1e-3,
GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &agbyield, &abserr);
368 double compute_snii_yield(gsl_interp2d * snii_interp,
const double * snii_weights,
double stellarmetal,
double masslow,
double masshigh, gsl_integration_workspace * gsl_work )
372 double yield = 0, abserr;
382 para.
interp = snii_interp;
388 if(masslow >= masshigh)
390 gsl_integration_qag(&ff, masslow, masshigh, 1e-7, 1e-3,
GSL_WORKSPACE, GSL_INTEG_GAUSS61, gsl_work, &yield, &abserr);
395 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)
401 double massyield = (agbyield + sniiyield)/imf_norm;
403 double Nsn1a =
sn1a_number(dtmyrstart, dtmyrend, hub);
411 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)
413 double MetalGenerated = 0;
417 MetalGenerated /= imf_norm;
425 MetalYields[i] /= imf_norm;
427 double Nsn1a =
sn1a_number(dtmyrstart, dtmyrend, hub);
432 return MetalGenerated;
439 int nthread = omp_get_max_threads();
443 for(i=0; i < nthread; i++)
462 #pragma omp parallel for reduction(+: haswork)
468 int tid = omp_get_thread_num();
469 const int slot =
P[p_i].PI;
472 double initialmass =
P[p_i].Mass +
STARP(p_i).TotalMassReturned;
478 if(
STARP(p_i).TotalMassReturned + priv->
MassReturn[slot] > initialmass * maxmassfrac) {
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;
509 for(i=0; i < omp_get_max_threads(); i++)
510 gsl_integration_workspace_free(priv->
gsl_work[i]);
536 MPI_Allreduce(&nwork, &totwork, 1,
MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
586 input->
Mass =
P[place].Mass;
587 input->
Hsml =
P[place].Hsml;
588 int pi =
P[place].PI;
590 double InitialMass =
P[place].Mass +
STARP(place).TotalMassReturned;
592 double dtmyrstart =
STARP(place).LastEnrichmentMyr;
593 int tid = omp_get_thread_num();
652 const double r2 = iter->
base.
r2;
653 const double r = iter->
base.
r;
655 if(r2 > 0 && r2 < iter->
kernel.HH)
666 int pi =
P[other].PI;
669 double volume =
P[other].Mass /
SPHP(other).Density;
681 SPHP(other).Metals[i] = (
SPHP(other).Metals[i] *
P[other].Mass + ThisMetals[i])/(
P[other].Mass + thismass);
683 SPHP(other).Metallicity = (
SPHP(other).Metallicity *
P[other].Mass + thismetal)/(
P[other].Mass + thismass);
685 double massfrac = (
P[other].Mass + thismass) /
P[other].Mass;
690 P[other].Mass *= massfrac;
694 SPHP(other).Density *= massfrac;
696 newmass =
P[other].Mass;
699 endrun(3,
"New mass %g new metal %g in particle %d id %ld from star mass %g metallicity %g\n",
762 #define STELLAR_DENSITY_GET_PRIV(tw) ((struct StellarDensityPriv*) ((tw)->priv))
774 int pi =
P[place].PI;
779 if(left == 0 && right > 0.99*tw->
tree->
BoxSize &&
P[place].Hsml == 0) {
782 if(
P[place].Hsml == 0)
791 left = 0.1 *
P[place].Hsml;
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);
803 for(i = 0; i <
NHSML; i++)
810 int pi =
P[place].PI;
814 for(i = 0; i < remote->
maxcmpte; i++) {
826 int tid = omp_get_thread_num();
831 double evalhsml[
NHSML];
832 for(j = 0; j < maxcmpt; j++)
833 evalhsml[j] =
effhsml(i, j, tw);
849 if((Right[pi] - Left[pi]) < 1.0e-4 * Left[pi])
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]);
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]);
880 for(i = 0; i <
NHSML; i++) {
891 const double r = iter->
base.
r;
892 const double r2 = iter->
base.
r2;
896 if(r2 < iter->
kernel[i].HH)
902 double thisvol =
P[other].Mass /
SPHP(other).Density;
912 for(i = 0; i <
NHSML; i++) {
913 if(O->
Ngb[i] > desnumngb) {
954 #pragma omp parallel for
970 #pragma omp parallel for
979 StarVolumeSPH[
P[a].PI] = priv->
VolumeSPH[
P[a].PI][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);
998 walltime_add(
"/SPH/Metals/Density/Misc", timeall - (timecomp + timewait + timecomm));
double hubble_function(const Cosmology *CP, double a)
double GetNumNgb(enum DensityKernelType KernelType)
enum DensityKernelType GetDensityKernelType(void)
double(* wk)(DensityKernel *kernel, double q)
double density_kernel_volume(DensityKernel *kernel)
void density_kernel_init(DensityKernel *kernel, double H, enum DensityKernelType type)
double density_kernel_wk(DensityKernel *kernel, double u)
void message(int where, const char *fmt,...)
void endrun(int where, const char *fmt,...)
void force_tree_rebuild_mask(ForceTree *tree, DomainDecomp *ddecomp, int mask, const int HybridNuGrav, const char *EmergencyOutputDir)
void force_tree_free(ForceTree *tree)
int force_get_father(int no, const ForceTree *tree)
static double kernel(double loga, void *params)
#define mymalloc(name, size)
#define ta_malloc(name, type, nele)
double param_get_double(ParameterSet *ps, const char *name)
int param_get_int(ParameterSet *ps, const char *name)
struct part_manager_type PartManager[1]
struct slots_manager_type SlotsManager[1]
void free_spinlocks(struct SpinLocks *spin)
void lock_spinlock(int i, struct SpinLocks *spin)
struct SpinLocks * init_spinlocks(int NumLock)
void unlock_spinlock(int i, struct SpinLocks *spin)
int64_t NumActiveParticle
MyFloat(* VolumeSPH)[NHSML]
enum NgbTreeFindSymmetric symmetric
DensityKernel kernel[NHSML]
double kernel_volume[NHSML]
TreeWalkHasWorkFunction haswork
size_t ngbiter_type_elsize
TreeWalkProcessFunction postprocess
TreeWalkNgbIterFunction ngbiter
TreeWalkReduceResultFunction reduce
TreeWalkVisitFunction visit
size_t result_type_elsize
TreeWalkFillQueryFunction fill
const double * metallicities
gsl_interp2d * lifetime_interp
gsl_interp_accel * massacc
gsl_interp_accel * metalacc
gsl_interp2d * lifetime_tables
int treewalk_visit_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
int treewalk_visit_nolist_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
double ngb_narrow_down(double *right, double *left, const double *radius, const double *numNgb, int maxcmpt, int desnumngb, int *closeidx, double BoxSize)
void treewalk_do_hsml_loop(TreeWalk *tw, int *queue, int64_t queuesize, int update_hsml)
int(* TreeWalkVisitFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, LocalTreeWalk *lv)
void(* TreeWalkReduceResultFunction)(const int j, TreeWalkResultBase *result, const enum TreeWalkReduceMode mode, TreeWalk *tw)
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
void(* TreeWalkNgbIterFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, TreeWalkNgbIterBase *iter, LocalTreeWalk *lv)
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
#define TREEWALK_REDUCE(A, B)
@ NGB_TREEFIND_ASYMMETRIC
#define walltime_measure(name)
#define walltime_add(name, dt)