void lineofsight_output(void) { char buf[500]; int n, s, next; double ti; next = find_next_lineofsighttime(All.Ti_nextlineofsight); ti = All.TimeBegin * exp(next * All.Timebase_interval); if(ThisTask == 0) { printf("Line of sight output! ThisTask=%d Time=%g NextTime=%g\n", ThisTask, All.Time, ti); fflush(stdout); } H_a = hubble_function(All.Time); Wmax = All.Time * H_a * All.BoxSize; if(ThisTask == 0) { sprintf(buf, "%s/los", All.OutputDir); mkdir(buf, 02755); } Los = mymalloc(sizeof(struct line_of_sight)); LosGlobal = mymalloc(sizeof(struct line_of_sight)); for(n = 0, s = 0; n < N_LOS; n++) { if(s + 3 >= RNDTABLE) { set_random_numbers(); s = 0; } Los->zaxis = (int) (3.0 * get_random_number(s++)); switch (Los->zaxis) { case 2: Los->xaxis = 0; Los->yaxis = 1; break; case 0: Los->xaxis = 1; Los->yaxis = 2; break; case 1: Los->xaxis = 2; Los->yaxis = 0; break; } Los->Xpos = All.BoxSize * get_random_number(s++); Los->Ypos = All.BoxSize * get_random_number(s++); #ifdef OUTPUTLINEOFSIGHT_SPECTRUM add_along_lines_of_sight(); sum_over_processors_and_normalize(); absorb_along_lines_of_sight(); output_lines_of_sight(n); #endif #ifdef OUTPUTLINEOFSIGHT_PARTICLES find_particles_and_save_them(n); #endif } myfree(LosGlobal); myfree(Los); }
void radtransfer_update_chemistry(void) { int i, j; double nH, temp, molecular_weight; double nHII; double dt, dtime, a3inv, c_light; double A, B, CC; double x; double n_gamma; double alpha_HII, gamma_HI; double total_nHI, total_V, total_nHI_all, total_V_all; #ifdef RT_INCLUDE_HE double nHe, alpha_HeII, alpha_HeIII, gamma_HeI, gamma_HeII; double nHe, nHeII, nHeIII; double y, D, E, F, G, J; double total_nHeI, total_nHeI_all; total_nHeI = 0; #endif total_nHI = total_V = 0; dt = (All.Radiation_Ti_endstep - All.Radiation_Ti_begstep) * All.Timebase_interval; if(All.ComovingIntegrationOn) { dtime = dt / hubble_function(All.Time); a3inv = 1.0 / All.Time / All.Time / All.Time; } else { dtime = dt; a3inv = 1.0; } c_light = C / All.UnitVelocity_in_cm_per_s; for(i = 0; i < N_gas; i++) if(P[i].Type == 0) { nH = (HYDROGEN_MASSFRAC * SphP[i].d.Density * a3inv) / (PROTONMASS / All.UnitMass_in_g * All.HubbleParam); molecular_weight = 4 / (1 + 3 * HYDROGEN_MASSFRAC + 4 * HYDROGEN_MASSFRAC * SphP[i].n_elec); temp = (SphP[i].Entropy + SphP[i].e.DtEntropy * dt) * pow(SphP[i].d.Density * a3inv, GAMMA_MINUS1) * (molecular_weight * PROTONMASS / All.UnitMass_in_g * All.HubbleParam) / (BOLTZMANN / All.UnitEnergy_in_cgs * All.HubbleParam); /* collisional ionization rate */ gamma_HI = 5.85e-11 * pow(temp, 0.5) * exp(-157809.1 / temp) / (1.0 + pow(temp / 1e5, 0.5)); gamma_HI *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; gamma_HI *= All.HubbleParam * All.HubbleParam; /* alpha_B recombination coefficient */ alpha_HII = 2.59e-13 * pow(temp / 1e4, -0.7); alpha_HII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; alpha_HII *= All.HubbleParam * All.HubbleParam; #ifdef RT_INCLUDE_HE nHe = ((1.0 - HYDROGEN_MASSFRAC) * SphP[i].d.Density * a3inv) / (4.0 * PROTONMASS / All.UnitMass_in_g * All.HubbleParam); /* collisional ionization rate */ gamma_HeI = 2.38e-11 * pow(temp, 0.5) * exp(-285335.4 / temp) / (1.0 + pow(temp / 1e5, 0.5)); gamma_HeI *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; gamma_HeI *= All.HubbleParam * All.HubbleParam; gamma_HeII = 5.68e-12 * pow(temp, 0.5) * exp(-631515 / temp) / (1.0 + pow(temp / 1e5, 0.5)); gamma_HeII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; gamma_HeII *= All.HubbleParam * All.HubbleParam; /* alpha_B recombination coefficient */ alpha_HeII = 1.5e-10 * pow(temp, -0.6353); alpha_HeII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; alpha_HeII *= All.HubbleParam * All.HubbleParam; alpha_HeIII = 3.36e-10 * pow(temp, -0.5) * pow(temp / 1e3, -0.2) / (1.0 + pow(temp / 1e6, 0.7)); alpha_HeIII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm; alpha_HeIII *= All.HubbleParam * All.HubbleParam; #endif for(j = 0; j < N_BINS; j++) { #ifdef RT_INCLUDE_HE x = SphP[i].nHI * nH * rt_sigma_HI[j] / (SphP[i].nHI * nH * rt_sigma_HI[j] + SphP[i].nHeI * nHe * rt_sigma_HeI[j] + SphP[i].nHeII * nHe * rt_sigma_HeII[j]); #else x = 1.0; #endif n_gamma = SphP[i].n_gamma[j] / P[i].Mass * a3inv; /* number of photons should be positive */ if(n_gamma < 0 || isnan(n_gamma)) { printf("NEGATIVE n_gamma: %g %d %d \n", n_gamma, i, ThisTask); printf("n_gamma[j] %g mass %g a3inv %g \n", SphP[i].n_gamma[j], P[i].Mass, a3inv); endrun(111); } A = dtime * gamma_HI * nH; B = dtime * c_light * rt_sigma_HI[j] * x; CC = dtime * alpha_HII* nH; /* semi-implicit scheme for ionization */ nHII = (SphP[i].nHII + B * n_gamma + A * SphP[i].n_elec) / (1.0 + B * n_gamma + CC * SphP[i].n_elec + A * SphP[i].n_elec); if(nHII < 0 || nHII > 1 || isnan(nHII)) { printf("ERROR nHII %g \n", nHII); endrun(333); } SphP[i].n_elec = nHII; SphP[i].nHII = nHII; SphP[i].nHI = 1.0 - nHII; #ifdef RT_INCLUDE_HE SphP[i].n_elec += SphP[i].nHeII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC); SphP[i].n_elec += 2.0 * SphP[i].nHeIII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC); y = SphP[i].nHeI * nHe * rt_sigma_HeI[j] / (SphP[i].nHI * nH * rt_sigma_HI[j] + SphP[i].nHeI * nHe * rt_sigma_HeI[j] + SphP[i].nHeII * nHe * rt_sigma_HeII[j]); D = dtime * gamma_HeII * nH; E = dtime * alpha_HeIII * nH; F = dtime * gamma_HeI * nH; G = dtime * c_light * rt_sigma_HeI[j] * y; J = dtime * alpha_HeII * nH; nHeII = SphP[i].nHeII + F * SphP[i].n_elec + G * n_gamma - ((F * SphP[i].n_elec + G * n_gamma - E * SphP[i].n_elec) / (1.0 + E * SphP[i].n_elec) * SphP[i].nHeIII); nHeII /= 1.0 + F * SphP[i].n_elec + G * n_gamma + D * SphP[i].n_elec + J * SphP[i].n_elec + ((F * SphP[i].n_elec + G * n_gamma - E * SphP[i].n_elec) / (1.0 + E * SphP[i].n_elec) * D * SphP[i].n_elec); if(nHeII < 0 || nHeII > 1 || isnan(nHeII)) { printf("ERROR neHII %g\n", nHeII); endrun(333); } nHeIII = (SphP[i].nHeIII + D * nHeII * SphP[i].n_elec) / (1.0 + E * SphP[i].n_elec); if(nHeIII < 0 || nHeIII > 1) { printf("ERROR nHeIII %g\n", nHeIII); endrun(222); } SphP[i].n_elec = SphP[i].nHII; SphP[i].n_elec += nHeII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC); SphP[i].n_elec += 2.0 * nHeIII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC); SphP[i].nHeII = nHeII; SphP[i].nHeIII = nHeIII; SphP[i].nHeI = 1.0 - SphP[i].nHeII - SphP[i].nHeIII; if(SphP[i].nHeI < 0 || SphP[i].nHeI > 1 || isnan(SphP[i].nHeI)) { printf("ERROR nHeI %g\n", SphP[i].nHeI); endrun(444); } #endif } #ifdef RT_INCLUDE_HE total_nHeI += SphP[i].nHeI * P[i].Mass / (SphP[i].d.Density * a3inv); #endif total_nHI += SphP[i].nHI * P[i].Mass / (SphP[i].d.Density * a3inv); total_V += P[i].Mass / (SphP[i].d.Density * a3inv); } MPI_Allreduce(&total_nHI, &total_nHI_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&total_V, &total_V_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #ifdef RT_INCLUDE_HE MPI_Allreduce(&total_nHeI, &total_nHeI_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #endif /* output the input of photon density in physical units */ if(ThisTask == 0) { fprintf(FdRad, "%g %g ", All.Time, total_nHI_all / total_V_all); #ifdef RT_INCLUDE_HE fprintf(FdRad, "%g\n", total_nHeI_all / total_V_all); #else fprintf(FdRad, "\n"); #endif fflush(FdRad); } }
void subfind_determine_sub_halo_properties(struct unbind_data *d, int num, double *totmass, double *pos, double *vel, double *cm, double *veldisp, double *vmax, double *vmaxrad, double *spin, MyIDType * mostboundid, double *halfmassrad, double *mass_tab) { int i, j, p; double s[3], v[3], max, vel_to_phys, H_of_a, atime, minpot; double lx, ly, lz, dv[3], dx[3], disp; double boxhalf, boxsize, ddxx; sort_r2list *rr_list = 0; int minindex; double mass, maxrad; boxsize = All.BoxSize; boxhalf = 0.5 * boxsize; if(All.ComovingIntegrationOn) { vel_to_phys = 1.0 / All.Time; H_of_a = hubble_function(All.Time); atime = All.Time; } else { vel_to_phys = atime = 1; H_of_a = 0; } for(i = 0, minindex = -1, minpot = 1.0e30; i < num; i++) { p = d[i].index; if(P[p].u.DM_Potential < minpot || minindex == -1) { minpot = P[p].u.DM_Potential; minindex = p; } } for(j = 0; j < 3; j++) pos[j] = P[minindex].Pos[j]; /* pos[] now holds the position of minimum potential */ /* we take it that as the center */ for(i = 0, minindex = -1, minpot = 1.0e30; i < num; i++) { p = d[i].index; if(P[p].v.DM_BindingEnergy < minpot || minindex == -1) { minpot = P[p].v.DM_BindingEnergy; minindex = p; } } *mostboundid = P[minindex].ID; /* let's get bulk velocity and the center-of-mass */ for(j = 0; j < 3; j++) s[j] = v[j] = 0; for(j = 0; j < 6; j++) mass_tab[j] = 0; for(i = 0, mass = 0; i < num; i++) { p = d[i].index; for(j = 0; j < 3; j++) { #ifdef PERIODIC ddxx = NEAREST(P[p].Pos[j] - pos[j]); #else ddxx = P[p].Pos[j] - pos[j]; #endif s[j] += P[p].Mass * ddxx; v[j] += P[p].Mass * P[p].Vel[j]; } mass += P[p].Mass; mass_tab[P[p].Type] += P[p].Mass; } *totmass = mass; for(j = 0; j < 3; j++) { s[j] /= mass; /* center of mass */ v[j] /= mass; vel[j] = vel_to_phys * v[j]; } for(j = 0; j < 3; j++) { s[j] += pos[j]; #ifdef PERIODIC while(s[j] < 0) s[j] += boxsize; while(s[j] >= boxsize) s[j] -= boxsize; #endif cm[j] = s[j]; } disp = lx = ly = lz = 0; rr_list = mymalloc(sizeof(sort_r2list) * num); for(i = 0; i < num; i++) { p = d[i].index; rr_list[i].r = 0; rr_list[i].mass = P[p].Mass; for(j = 0; j < 3; j++) { #ifdef PERIODIC ddxx = NEAREST(P[p].Pos[j] - s[j]); #else ddxx = P[p].Pos[j] - s[j]; #endif dx[j] = atime * ddxx; dv[j] = vel_to_phys * (P[p].Vel[j] - v[j]); dv[j] += H_of_a * dx[j]; disp += P[p].Mass * dv[j] * dv[j]; /* for rotation curve computation, take minimum of potential as center */ #ifdef PERIODIC ddxx = NEAREST(P[p].Pos[j] - pos[j]); #else ddxx = P[p].Pos[j] - pos[j]; #endif ddxx = atime * ddxx; rr_list[i].r += ddxx * ddxx; } lx += P[p].Mass * (dx[1] * dv[2] - dx[2] * dv[1]); ly += P[p].Mass * (dx[2] * dv[0] - dx[0] * dv[2]); lz += P[p].Mass * (dx[0] * dv[1] - dx[1] * dv[0]); rr_list[i].r = sqrt(rr_list[i].r); } *veldisp = sqrt(disp / (3 * mass)); /* convert to 1d velocity dispersion */ spin[0] = lx / mass; spin[1] = ly / mass; spin[2] = lz / mass; qsort(rr_list, num, sizeof(sort_r2list), subfind_compare_dist_rotcurve); *halfmassrad = rr_list[num / 2].r; /* compute cumulative mass */ for(i = 1; i < num; i++) rr_list[i].mass = rr_list[i - 1].mass + rr_list[i].mass; for(i = num - 1, max = 0, maxrad = 0; i > 5; i--) if(rr_list[i].mass / rr_list[i].r > max) { max = rr_list[i].mass / rr_list[i].r; maxrad = rr_list[i].r; } *vmax = sqrt(All.G * max); *vmaxrad = maxrad; myfree(rr_list); }
int subfind_unbind(struct unbind_data *ud, int len) { double *bnd_energy, energy_limit, weakly_bound_limit = 0; int i, j, p, minindex, unbound, phaseflag; double ddxx, s[3], dx[3], v[3], dv[3], pos[3]; double vel_to_phys, H_of_a, atime, pot, minpot = 0; double boxsize, boxhalf; double TotMass; boxsize = All.BoxSize; boxhalf = 0.5 * All.BoxSize; if(All.ComovingIntegrationOn) { vel_to_phys = 1.0 / All.Time; H_of_a = hubble_function(All.Time); atime = All.Time; } else { vel_to_phys = atime = 1; H_of_a = 0; } bnd_energy = (double *) mymalloc(len * sizeof(double)); phaseflag = 0; /* this means we will recompute the potential for all particles */ do { subfind_loctree_treebuild(len, ud); /* let's compute the potential */ if(phaseflag == 0) /* redo it for all the particles */ { for(i = 0, minindex = -1, minpot = 1.0e30; i < len; i++) { p = ud[i].index; pot = subfind_loctree_treeevaluate_potential(p); /* note: add self-energy */ P[p].u.DM_Potential = pot + P[p].Mass / All.SofteningTable[P[p].Type]; P[p].u.DM_Potential *= All.G / atime; if(All.TotN_gas > 0 && (FOF_PRIMARY_LINK_TYPES & 1) == 0 && All.OmegaBaryon > 0) P[p].u.DM_Potential *= All.Omega0 / (All.Omega0 - All.OmegaBaryon); if(P[p].u.DM_Potential < minpot || minindex == -1) { minpot = P[p].u.DM_Potential; minindex = p; } } for(j = 0; j < 3; j++) pos[j] = P[minindex].Pos[j]; /* position of minimum potential */ } else { /* we only repeat for those close to the unbinding threshold */ for(i = 0; i < len; i++) { p = ud[i].index; if(P[p].v.DM_BindingEnergy >= weakly_bound_limit) { pot = subfind_loctree_treeevaluate_potential(p); /* note: add self-energy */ P[p].u.DM_Potential = pot + P[p].Mass / All.SofteningTable[P[p].Type]; P[p].u.DM_Potential *= All.G / atime; if(All.TotN_gas > 0 && (FOF_PRIMARY_LINK_TYPES & 1) == 0 && All.OmegaBaryon > 0) P[p].u.DM_Potential *= All.Omega0 / (All.Omega0 - All.OmegaBaryon); } } } /* let's get bulk velocity and the center-of-mass */ v[0] = v[1] = v[2] = 0; s[0] = s[1] = s[2] = 0; for(i = 0, TotMass = 0; i < len; i++) { p = ud[i].index; for(j = 0; j < 3; j++) { #ifdef PERIODIC ddxx = NEAREST(P[p].Pos[j] - pos[j]); #else ddxx = P[p].Pos[j] - pos[j]; #endif s[j] += P[p].Mass * ddxx; v[j] += P[p].Mass * P[p].Vel[j]; } TotMass += P[p].Mass; } for(j = 0; j < 3; j++) { v[j] /= TotMass; s[j] /= TotMass; /* center-of-mass */ s[j] += pos[j]; #ifdef PERIODIC while(s[j] < 0) s[j] += boxsize; while(s[j] >= boxsize) s[j] -= boxsize; #endif } for(i = 0; i < len; i++) { p = ud[i].index; for(j = 0; j < 3; j++) { dv[j] = vel_to_phys * (P[p].Vel[j] - v[j]); #ifdef PERIODIC dx[j] = atime * NEAREST(P[p].Pos[j] - s[j]); #else dx[j] = atime * (P[p].Pos[j] - s[j]); #endif dv[j] += H_of_a * dx[j]; } P[p].v.DM_BindingEnergy = P[p].u.DM_Potential + 0.5 * (dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2]); #ifdef DENSITY_SPLIT_BY_TYPE if(P[p].Type == 0) P[p].v.DM_BindingEnergy += P[p].w.int_energy; #endif bnd_energy[i] = P[p].v.DM_BindingEnergy; } qsort(bnd_energy, len, sizeof(double), subfind_compare_binding_energy); /* largest comes first! */ energy_limit = bnd_energy[(int) (0.25 * len)]; for(i = 0, unbound = 0; i < len - 1; i++) { if(bnd_energy[i] > 0) unbound++; else unbound--; if(unbound <= 0) break; } weakly_bound_limit = bnd_energy[i]; /* now omit unbound particles, but at most 1/4 of the original size */ for(i = 0, unbound = 0; i < len; i++) { p = ud[i].index; if(P[p].v.DM_BindingEnergy > 0 && P[p].v.DM_BindingEnergy > energy_limit) { unbound++; ud[i] = ud[len - 1]; i--; len--; } } if(len < All.DesLinkNgb) break; if(phaseflag == 0) { if(unbound > 0) phaseflag = 1; } else { if(unbound == 0) { phaseflag = 0; /* this will make us repeat everything once more for all particles */ unbound = 1; } } } while(unbound > 0); myfree(bnd_energy); return (len); }
void cosmic_ray_diffusion(void) { int i, iter; double CR_E0_delta0, CR_E0_delta1, CR_E0_alpha, CR_E0_beta; double CR_n0_delta0, CR_n0_delta1, CR_n0_alpha, CR_n0_beta; double a3inv, dt, rel_change, loc_max_rel_change, glob_max_rel_change; double sumnew, sumold, sumtransfer, sumnew_tot, sumold_tot, sumtransfer_tot; double kappa, kappa_egy, CR_q_i, cr_efac_i; double meanKineticEnergy, qmeanKin; int CRpop; if(ThisTask == 0) { printf("Start cosmic ray diffusion...\n"); fflush(stdout); } for(CRpop = 0; CRpop < NUMCRPOP; CRpop++) { CR_E0[CRpop] = (double *) mymalloc("CR_E0[CRpop]", N_gas * sizeof(double)); CR_E0_Old[CRpop] = (double *) mymalloc("CR_E0_Old[CRpop]", N_gas * sizeof(double)); CR_E0_Kappa[CRpop] = (double *) mymalloc("CR_E0_Kappa[CRpop]", N_gas * sizeof(double)); } CR_E0_Residual = (double *) mymalloc("CR_E0_Residual", N_gas * sizeof(double)); CR_E0_DVec = (double *) mymalloc("CR_E0_DVec", N_gas * sizeof(double)); CR_E0_QVec = (double *) mymalloc("CR_E0_QVec", N_gas * sizeof(double)); for(CRpop = 0; CRpop < NUMCRPOP; CRpop++) { CR_n0[CRpop] = (double *) mymalloc("CR_n0[CRpop]", N_gas * sizeof(double)); CR_n0_Old[CRpop] = (double *) mymalloc("CR_n0_Old[CRpop]", N_gas * sizeof(double)); CR_n0_Kappa[CRpop] = (double *) mymalloc("CR_n0_Kappa[CRpop]", N_gas * sizeof(double)); } CR_n0_Residual = (double *) mymalloc("CR_n0_Residual", N_gas * sizeof(double)); CR_n0_DVec = (double *) mymalloc("CR_n0_DVec", N_gas * sizeof(double)); CR_n0_QVec = (double *) mymalloc("CR_n0_QVec", N_gas * sizeof(double)); if(All.ComovingIntegrationOn) a3inv = 1 / (All.Time * All.Time * All.Time); else a3inv = 1.0; dt = (All.CR_Diffusion_Ti_endstep - All.CR_Diffusion_Ti_begstep) * All.Timebase_interval; if(All.ComovingIntegrationOn) dt *= All.Time / hubble_function(All.Time); if(ThisTask == 0) { printf("dt=%g\n", dt); } /* First, let's compute the diffusivities for each particle */ for(i = 0; i < N_gas; i++) { if(P[i].Type == 0) { for(CRpop = 0; CRpop < NUMCRPOP; CRpop++) { CR_E0[CRpop][i] = CR_E0_Old[CRpop][i] = SphP[i].CR_E0[CRpop]; CR_n0[CRpop][i] = CR_n0_Old[CRpop][i] = SphP[i].CR_n0[CRpop]; kappa = All.CR_DiffusionCoeff; if(All.CR_DiffusionDensScaling != 0.0) kappa *= pow(SphP[i].d.Density * a3inv / All.CR_DiffusionDensZero, All.CR_DiffusionDensScaling); if(All.CR_DiffusionEntropyScaling != 0.0) kappa *= pow(SphP[i].Entropy / All.CR_DiffusionEntropyZero, All.CR_DiffusionEntropyScaling); if(SphP[i].CR_E0[CRpop] > 0) { CR_q_i = SphP[i].CR_q0[CRpop] * pow(SphP[i].d.Density * a3inv, 0.33333); cr_efac_i = CR_Tab_MeanEnergy(CR_q_i, All.CR_Alpha[CRpop] - 0.3333) / CR_Tab_MeanEnergy(CR_q_i, All.CR_Alpha[CRpop]); kappa *= (All.CR_Alpha[CRpop] - 1) / (All.CR_Alpha[CRpop] - 1.33333) * pow(CR_q_i, 0.3333); kappa_egy = kappa * cr_efac_i; } else kappa_egy = kappa; CR_E0_Kappa[CRpop][i] = kappa_egy; CR_n0_Kappa[CRpop][i] = kappa; /* we'll factor the timestep into the diffusivities, for simplicity */ CR_E0_Kappa[CRpop][i] *= dt; CR_n0_Kappa[CRpop][i] *= dt; } } } /* Let's start the Conjugate Gradient Algorithm */ /* Initialization */ for(CRpop = 0; CRpop < NUMCRPOP; CRpop++) { cosmic_ray_diffusion_matrix_multiply(CR_E0_Old[CRpop], CR_E0_Residual, CR_n0_Old[CRpop], CR_n0_Residual, CRpop); for(i = 0; i < N_gas; i++) { if(P[i].Type == 0) { CR_E0_Residual[i] = CR_E0_Old[CRpop][i] - CR_E0_Residual[i]; CR_E0_DVec[i] = CR_E0_Residual[i]; CR_n0_Residual[i] = CR_n0_Old[CRpop][i] - CR_n0_Residual[i]; CR_n0_DVec[i] = CR_n0_Residual[i]; } } CR_E0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_E0_Residual, CR_E0_Residual); CR_E0_delta0 = CR_E0_delta1; CR_n0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_n0_Residual, CR_n0_Residual); CR_n0_delta0 = CR_n0_delta1; iter = 0; /* iteration counter */ glob_max_rel_change = 1 + CR_DIFFUSION_ITER_ACCURACY; /* to make sure that we enter the iteration */ while(iter < MAX_CR_DIFFUSION_ITER && glob_max_rel_change > CR_DIFFUSION_ITER_ACCURACY && CR_E0_delta1 > 0) { cosmic_ray_diffusion_matrix_multiply(CR_E0_DVec, CR_E0_QVec, CR_n0_DVec, CR_n0_QVec, CRpop); CR_E0_alpha = CR_E0_delta1 / cosmic_ray_diffusion_vector_multiply(CR_E0_DVec, CR_E0_QVec); CR_n0_alpha = CR_n0_delta1 / cosmic_ray_diffusion_vector_multiply(CR_n0_DVec, CR_n0_QVec); for(i = 0, loc_max_rel_change = 0; i < N_gas; i++) { CR_E0[CRpop][i] += CR_E0_alpha * CR_E0_DVec[i]; CR_E0_Residual[i] -= CR_E0_alpha * CR_E0_QVec[i]; CR_n0[CRpop][i] += CR_n0_alpha * CR_n0_DVec[i]; CR_n0_Residual[i] -= CR_n0_alpha * CR_n0_QVec[i]; if(CR_E0[CRpop][i] > 0) { rel_change = CR_E0_alpha * CR_E0_DVec[i] / CR_E0[CRpop][i]; if(loc_max_rel_change < rel_change) loc_max_rel_change = rel_change; } if(CR_n0[CRpop][i] > 0) { rel_change = CR_n0_alpha * CR_n0_DVec[i] / CR_n0[CRpop][i]; if(loc_max_rel_change < rel_change) loc_max_rel_change = rel_change; } } CR_E0_delta0 = CR_E0_delta1; CR_E0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_E0_Residual, CR_E0_Residual); CR_n0_delta0 = CR_n0_delta1; CR_n0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_n0_Residual, CR_n0_Residual); CR_E0_beta = CR_E0_delta1 / CR_E0_delta0; CR_n0_beta = CR_n0_delta1 / CR_n0_delta0; for(i = 0; i < N_gas; i++) { CR_E0_DVec[i] = CR_E0_Residual[i] + CR_E0_beta * CR_E0_DVec[i]; CR_n0_DVec[i] = CR_n0_Residual[i] + CR_n0_beta * CR_n0_DVec[i]; } iter++; MPI_Allreduce(&loc_max_rel_change, &glob_max_rel_change, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); if(ThisTask == 0) { printf ("cosmic ray diffusion iter=%d CR_E0_delta1=%g delta1/delta0=%g CR_n0_delta1=%g delta1/delta0=%g max-rel-change=%g\n", iter, CR_E0_delta1, CR_E0_delta1 / CR_E0_delta0, CR_n0_delta1, CR_n0_delta1 / CR_n0_delta0, glob_max_rel_change); fflush(stdout); } } /* Now we have the solution vectors */ /* set the new cosmic ray prorperties */ for(i = 0, sumnew = sumold = sumtransfer = 0; i < N_gas; i++) { if(P[i].Type == 0) { SphP[i].CR_E0[CRpop] = CR_E0[CRpop][i]; SphP[i].CR_n0[CRpop] = CR_n0[CRpop][i]; SphP[i].CR_DeltaE[CRpop] = 0; SphP[i].CR_DeltaN[CRpop] = 0; if(SphP[i].CR_n0[CRpop] > 1.0e-12 && SphP[i].CR_E0[CRpop] > 0) { meanKineticEnergy = SphP[i].CR_E0[CRpop] * m_p / SphP[i].CR_n0[CRpop]; qmeanKin = CR_q_from_mean_kinetic_energy(meanKineticEnergy, CRpop); SphP[i].CR_q0[CRpop] = qmeanKin * pow(SphP[i].d.Density * a3inv, -(1.0 / 3.0)); SphP[i].CR_C0[CRpop] = SphP[i].CR_n0[CRpop] * (All.CR_Alpha[CRpop] - 1.0) * pow(SphP[i].CR_q0[CRpop], All.CR_Alpha[CRpop] - 1.0); } else { SphP[i].CR_E0[CRpop] = 0.0; SphP[i].CR_n0[CRpop] = 0.0; SphP[i].CR_q0[CRpop] = 1.0e10; SphP[i].CR_C0[CRpop] = 0.0; } sumnew += CR_E0[CRpop][i]; sumold += CR_E0_Old[CRpop][i]; sumtransfer += fabs(CR_E0[CRpop][i] - CR_E0_Old[CRpop][i]); } } MPI_Allreduce(&sumnew, &sumnew_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&sumold, &sumold_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Allreduce(&sumtransfer, &sumtransfer_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); if(ThisTask == 0) { printf ("\ncosmic ray diffusion finished. energy_before=%g energy_after=%g rel-change=%g rel-transfer=%g\n\n", sumold_tot, sumnew_tot, sumold_tot ? ((sumnew_tot - sumold_tot) / sumold_tot) : 0.0, sumold_tot ? (sumtransfer_tot / sumold_tot) : 0.0); fflush(stdout); } } myfree(CR_E0_QVec); myfree(CR_E0_DVec); myfree(CR_E0_Residual); myfree(CR_n0_QVec); myfree(CR_n0_DVec); myfree(CR_n0_Residual); for(CRpop = 0; CRpop < NUMCRPOP; CRpop++) { myfree(CR_n0_Kappa[CRpop]); myfree(CR_n0_Old[CRpop]); myfree(CR_n0[CRpop]); myfree(CR_E0_Kappa[CRpop]); myfree(CR_E0_Old[CRpop]); myfree(CR_E0[CRpop]); } }
void radtransfer(void) { int i, j, iter; double alpha_cg, beta, delta_old, delta_new, sum, old_sum, min_diag, glob_min_diag, max_diag, glob_max_diag; double timestep, nH, je=0; double rel, res, maxrel, glob_maxrel; double DQ; NextActiveParticleRT = (int *) mymalloc(N_gas * sizeof(int)); XVec = (double *) mymalloc(N_gas * sizeof(double)); QVec = (double *) mymalloc(N_gas * sizeof(double)); DVec = (double *) mymalloc(N_gas * sizeof(double)); Residue = (double *) mymalloc(N_gas * sizeof(double)); Kappa = (double *) mymalloc(N_gas * sizeof(double)); Lambda = (double *) mymalloc(N_gas * sizeof(double)); Diag = (double *) mymalloc(N_gas * sizeof(double)); Zvec = (double *) mymalloc(N_gas * sizeof(double)); Diag2 = (double *) mymalloc(N_gas * sizeof(double)); c_light = C / All.UnitVelocity_in_cm_per_s; sigma = 6.3e-18 / All.UnitLength_in_cm / All.UnitLength_in_cm * All.HubbleParam * All.HubbleParam;; /* the actual time-step we need to do */ timestep = (All.Radiation_Ti_endstep - All.Radiation_Ti_begstep) * All.Timebase_interval; if(All.ComovingIntegrationOn) { a3inv = 1 / (All.Time * All.Time * All.Time); hubble_a = hubble_function(All.Time); /* in comoving case, timestep is dloga at this point. Convert to dt */ timestep /= hubble_a; } else { a3inv = hubble_a = 1.0; } //radtransfer_get_active(); dt = timestep / NSTEP; for(i = 0; i < NSTEP; i++) { if(ThisTask == 0) { printf("%s %i\n", "the step is ", i); printf("%s %g\n", "c_light is ", c_light); printf("%s %g\n", "dt is ", dt); fflush(stdout); } /* initialization for the CG method */ for(j = 0; j < N_gas; j++) if(P[j].Type == 0) #ifdef RT_VAR_DT if(SphP[j].rt_flag == 1) #endif { XVec[j] = SphP[j].n_gamma; nH = (SphP[j].d.Density * a3inv) / (PROTONMASS / All.UnitMass_in_g * All.HubbleParam); //physical Kappa[j] = (SphP[j].nHI + 1.0e-8) * nH * sigma; //physical /* physical kappa = 1/distance => comoving is 1/(distance/a) = a/distance = a * kappa */ if(All.ComovingIntegrationOn) Kappa[j] = (Kappa[j] + 3.0 * hubble_a / c_light) * All.Time; //comoving #ifdef RADTRANSFER_FLUXLIMITER /* now calculate flux limiter */ if(SphP[j].n_gamma > 0) { double R = sqrt(SphP[j].Grad_ngamma[0] * SphP[j].Grad_ngamma[0] + SphP[j].Grad_ngamma[1] * SphP[j].Grad_ngamma[1] + SphP[j].Grad_ngamma[2] * SphP[j].Grad_ngamma[2]) / (SphP[j].n_gamma * Kappa[j]); if(All.ComovingIntegrationOn) R /= All.Time; Lambda[j] = (1+R)/(1+R+R*R); if(Lambda[j] < 1e-100) Lambda[j] = 0; } else Lambda[j] = 1.0; #endif } /* add the source term */ for(j = 0; j < N_gas; j++) if(P[j].Type == 0) #ifdef RT_VAR_DT if(SphP[j].rt_flag == 1) #endif { SphP[j].n_gamma += dt * SphP[j].Je * P[j].Mass; if(SphP[j].Je) je+=SphP[j].Je; } // printf("glowing particles lum %g \n", je); radtransfer_matrix_multiply(XVec, Residue, Diag); for(j = 0; j < N_gas; j++) if(P[j].Type == 0) #ifdef RT_VAR_DT if(SphP[j].rt_flag == 1) #endif Residue[j] = SphP[j].n_gamma - Residue[j]; /* Let's take the diagonal matrix elements as Jacobi preconditioner */ for(j = 0, min_diag = MAX_REAL_NUMBER, max_diag = -MAX_REAL_NUMBER; j < N_gas; j++) if(P[j].Type == 0) #ifdef RT_VAR_DT if(SphP[j].rt_flag == 1) #endif { /* note: in principle we would have to substract the w_ii term, but this is always zero */ if(Diag[j] < min_diag) min_diag = Diag[j]; if(Diag[j] > max_diag) max_diag = Diag[j]; Zvec[j] = Residue[j] / Diag[j]; DVec[j] = Zvec[j]; } MPI_Allreduce(&min_diag, &glob_min_diag, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); MPI_Allreduce(&max_diag, &glob_max_diag, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); delta_new = radtransfer_vector_multiply(Zvec, Residue); delta_old = delta_new; old_sum = radtransfer_vector_sum(XVec); if(ThisTask == 0) printf("\nBegin CG iteration\nold |x|=%g, min-diagonal=%g, max-diagonal=%g\n", old_sum, glob_min_diag, glob_max_diag); /* begin the CG method iteration */ iter = 0; do { radtransfer_matrix_multiply(DVec, QVec, Diag2); DQ = radtransfer_vector_multiply(DVec, QVec); if(DQ == 0) alpha_cg = 0; else alpha_cg = delta_new / DQ; for(j = 0, maxrel = 0; j < N_gas; j++) { XVec[j] += alpha_cg * DVec[j]; Residue[j] -= alpha_cg * QVec[j]; Zvec[j] = Residue[j] / Diag[j]; rel = fabs(alpha_cg * DVec[j]) / (XVec[j] + 1.0e-10); if(rel > maxrel) maxrel = rel; } delta_old = delta_new; delta_new = radtransfer_vector_multiply(Zvec, Residue); sum = radtransfer_vector_sum(XVec); res = radtransfer_vector_sum(Residue); if(delta_old) beta = delta_new / delta_old; else beta = 0; for(j = 0; j < N_gas; j++) DVec[j] = Zvec[j] + beta * DVec[j]; MPI_Allreduce(&maxrel, &glob_maxrel, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); if(ThisTask == 0) { printf("radtransfer: iter=%3d |res|/|x|=%12.6g maxrel=%12.6g |x|=%12.6g | res|=%12.6g\n", iter, res/sum, glob_maxrel, sum, res); fflush(stdout); } iter++; } while((res > ACCURACY * sum && glob_maxrel > ACCURACY && iter < MAX_ITER) || iter < 2); if(ThisTask == 0) printf("\n"); /* update the intensity */ for(j = 0; j < N_gas; j++) if(P[j].Type == 0) #ifdef RT_VAR_DT if(SphP[j].rt_flag == 1) #endif { if(XVec[j] < 0 && XVec[j] > -EPSILON) XVec[j] = 0; SphP[j].n_gamma = XVec[j]; } /* update the chemistry */ radtransfer_update_chemistry(); } myfree(Diag2); myfree(Zvec); myfree(Diag); myfree(Lambda); myfree(Kappa); myfree(Residue); myfree(DVec); myfree(QVec); myfree(XVec); myfree(NextActiveParticleRT); }