//Age in Mpc/Km/s/h - code units void update_massweightage(int p, double stars, double time) { int outputbin; double age; for(outputbin = 0; outputbin < NOUT; outputbin++) { age = time - NumToTime(ListOutputSnaps[outputbin]); #ifdef DETAILED_METALS_AND_MASS_RETURN Gal[p].MassWeightAge[outputbin] += age * stars; #else Gal[p].MassWeightAge[outputbin] += age * stars * (1. - RecycleFraction); #endif } }
void write_sfh_bins() { FILE* SFH_Bins_File; struct SFH_Time *sfh_times; char buf[1000]; /* sprintf(buf, "%s/SFH_Bins.csv", FinalOutputDir); if(!(SFH_Bins_File = fopen(buf, "w"))) { char sbuf[1000]; sprintf(sbuf, "can't open file `%s'\n", buf); terminate(sbuf); } else printf("writing sfh bins to %s\n", buf); */ int snap,j, nbins,ibin; nbins = 0; for(snap = 0; snap < MAXSNAPS; snap++) { for(j=0;j < SFH_ibin[snap][0];j++) { nbins++; // TODO writing as CSV is temporary test for checking output in binary /* fprintf(SFH_Bins_File,"%d,%d,%f,%f,%f,%f,%d,%d\r\n", snap,j,SFH_t[snap][0][j],SFH_dt[snap][0][j], (SFH_t[snap][0][j]+SFH_dt[snap][0][j]/2.-NumToTime(snap))*UnitTime_in_years/Hubble_h, SFH_dt[snap][0][j]*UnitTime_in_years/Hubble_h, SFH_Nbins[snap][0][j],SFH_ibin[snap][0]); */ } } // fflush(SFH_Bins_File); // fclose(SFH_Bins_File); sfh_times = (struct SFH_Time *) mymalloc("sfh_times", sizeof(struct SFH_Time) * nbins); ibin = 0; for(snap = 0; snap < MAXSNAPS; snap++) { for(j=0;j < SFH_ibin[snap][0];j++) { sfh_times[ibin].snapnum = snap; sfh_times[ibin].bin = j; sfh_times[ibin].lookbacktime = (SFH_t[snap][0][j]+SFH_dt[snap][0][j]/2.-NumToTime(snap))*UnitTime_in_years/Hubble_h; sfh_times[ibin].dt=SFH_dt[snap][0][j]*UnitTime_in_years/Hubble_h; sfh_times[ibin].nbins = SFH_Nbins[snap][0][j]; ibin++; } } sprintf(buf, "%s/SFH_Bins", FinalOutputDir); if(!(SFH_Bins_File = fopen(buf, "w"))) { char sbuf[1000]; sprintf(sbuf, "can't open file `%s'\n", buf); terminate(sbuf); } else printf("writing sfh bins to %s\n", buf); // write # bins myfwrite(&nbins, sizeof(int), 1, SFH_Bins_File); // write 1 // skip header myfseek(SFH_Bins_File, sizeof(struct SFH_Time), SEEK_SET); myfwrite(sfh_times, sizeof(struct SFH_Time), nbins, SFH_Bins_File); // size of an output structure (Galaxy_Output) fflush(SFH_Bins_File); fclose(SFH_Bins_File); }
void prepare_galaxy_for_output(int n, struct GALAXY *g, struct GALAXY_OUTPUT *o) #endif { int j,ibin; #ifndef NO_PROPS_OUTPUTS o->Type = g->Type; o->SnapNum = g->SnapNum; o->CentralMvir = get_virial_mass(Halo[g->HaloNr].FirstHaloInFOFgroup); o->CentralRvir = get_virial_radius(Halo[g->HaloNr].FirstHaloInFOFgroup); o->Mvir = g->Mvir; o->Rvir = g->Rvir; o->Vvir = g->Vvir; for(j = 0; j < 3; j++) { o->Pos[j] = g->Pos[j]; o->DistanceToCentralGal[j] = wrap(Halo[Halo[g->HaloNr].FirstHaloInFOFgroup].Pos[j] - g->Pos[j],BoxSize);; } o->ColdGas = g->ColdGas; o->DiskMass = g->DiskMass; o->BulgeMass = g->BulgeMass; o->HotGas = g->HotGas; o->BlackHoleMass = g->BlackHoleMass; #endif #ifdef COMPUTE_SPECPHOT_PROPERTIES #ifndef POST_PROCESS_MAGS #ifdef OUTPUT_REST_MAGS /* Luminosities are converted into Mags in various bands */ for(j = 0; j < NMAG; j++) o->Mag[j] = lum_to_mag(g->Lum[j][n]); #endif #endif //ndef POST_PROCESS_MAGS #endif //COMPUTE_SPECPHOT_PROPERTIES #ifndef LIGHT_OUTPUT #ifndef NO_PROPS_OUTPUTS #ifdef GALAXYTREE o->HaloID = HaloIDs[g->HaloNr].HaloID; o->Redshift = ZZ[g->SnapNum]; int ii = (int) floor(o->Pos[0] * ScaleFactor); int jj = (int) floor(o->Pos[1] * ScaleFactor); int kk = (int) floor(o->Pos[2] * ScaleFactor); o->PeanoKey = peano_hilbert_key(ii, jj, kk, Hashbits); o->SubID = calc_big_db_subid_index(g->SnapNum, Halo[g->HaloNr].FileNr, Halo[g->HaloNr].SubhaloIndex); int tmpfirst = Halo[g->HaloNr].FirstHaloInFOFgroup; int lenmax = 0; int next = tmpfirst; while(next != -1) { if(Halo[next].Len > lenmax) { lenmax = Halo[next].Len; tmpfirst = next; } next = Halo[next].NextHaloInFOFgroup; } o->MMSubID = calc_big_db_subid_index(g->SnapNum, Halo[tmpfirst].FileNr, Halo[tmpfirst].SubhaloIndex); #endif o->LookBackTimeToSnap = NumToTime(g->SnapNum)*UnitTime_in_years/Hubble_h; o->InfallVmax = g->InfallVmax; o->InfallSnap = g->InfallSnap; o-> InfallHotGas = g-> InfallHotGas; o->HotRadius = g->HotRadius; #ifdef HALOPROPERTIES o->HaloM_Mean200 = g->HaloM_Mean200; o->HaloM_Crit200 = g->HaloM_Crit200; o->HaloM_TopHat = g->HaloM_TopHat; o->HaloVelDisp = g->HaloVelDisp; o->HaloVmax = g->HaloVmax; #endif o->Len = g->Len; o->Vmax = g->Vmax; o->BulgeSize = g->BulgeSize; o->EjectedMass = g->EjectedMass; o->BlackHoleGas = g->BlackHoleGas; for(j = 0; j < 3; j++) { o->Vel[j] = g->Vel[j]; #ifdef HALOSPIN o->HaloSpin[j] = g->HaloSpin[j]; #endif #ifndef H2_AND_RINGS o->GasSpin[j] = g->GasSpin[j]; o->StellarSpin[j] = g->StellarSpin[j]; #else o->DiskSpin[j] = g->DiskSpin[j]; #endif #ifdef HALOPROPERTIES o->HaloPos[j] = g->HaloPos[j]; o->HaloVel[j] = g->HaloVel[j]; o->HaloSpin[j] = g->HaloSpin[j]; #endif } o->XrayLum = g->XrayLum; o->GasDiskRadius = g->GasDiskRadius; o->StellarDiskRadius = g->StellarDiskRadius; o->CoolingRadius = g->CoolingRadius; o->ICM = g->ICM; //o->MetalsICM = CORRECTDBFLOAT(g->MetalsICM); o->MetalsICM = g->MetalsICM; o->QuasarAccretionRate = g->QuasarAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; o->RadioAccretionRate = g->RadioAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; o->CosInclination = g->CosInclination; if(g->Type == 2 || (g->Type == 1 && g->MergeOn == 1)) { o->OriMergTime=g->OriMergTime; o->MergTime = g->MergTime; } else { o->OriMergTime=0.0; o->MergTime = 0.0; } #ifndef GALAXYTREE o->HaloIndex = g->HaloNr; #endif #ifdef MBPID o->MostBoundID = g->MostBoundID; #endif #ifdef GALAXYTREE o->DisruptOn = g->DisruptOn; #endif #ifdef MERGE01 o->MergeOn = g->MergeOn; #endif //METALS /*o->MetalsColdGas = CORRECTDBFLOAT(g->MetalsColdGas); o->MetalsDiskMass = CORRECTDBFLOAT(g->MetalsDiskMass); o->MetalsBulgeMass = CORRECTDBFLOAT(g->MetalsBulgeMass); o->MetalsHotGas = CORRECTDBFLOAT(g->MetalsHotGas); o->MetalsEjectedMass = CORRECTDBFLOAT(g->MetalsEjectedMass); #ifdef METALS_SELF o->MetalsHotGasSelf = CORRECTDBFLOAT(g->MetalsHotGasSelf); #endif*/ o->MetalsColdGas = g->MetalsColdGas; o->MetalsDiskMass = g->MetalsDiskMass; o->MetalsBulgeMass = g->MetalsBulgeMass; o->MetalsHotGas = g->MetalsHotGas; o->MetalsEjectedMass = g->MetalsEjectedMass; #ifdef METALS_SELF o->MetalsHotGasSelf = g->MetalsHotGasSelf; #endif #ifdef TRACK_BURST o->BurstMass=g->BurstMass; #endif #ifdef H2_AND_RINGS for(j=0; j<RNUM; j++) { o->H2fractionr[j] = g -> H2fractionr[j]; o->ColdGasr[j] = g->ColdGasr[j]; o->DiskMassr[j] = g->DiskMassr[j]; o->MetalsColdGasr[j] = g->MetalsColdGasr[j]; o->MetalsDiskMassr[j] = g->MetalsDiskMassr[j]; } #endif //STAR FORMATION HISTORIES / RATES #ifdef STAR_FORMATION_HISTORY o->sfh_ibin=g->sfh_ibin; ibin=0; for (j=0;j<=o->sfh_ibin;j++) { #ifndef NORMALIZEDDB // o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.-NumToTime(g->SnapNum))*UnitTime_in_years/Hubble_h; //Time from middle of this sfh bin to snapshot - converted from code units to years //o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.)*UnitTime_in_years/Hubble_h; //ROB: Lookback time to middle of SFH bin, in years //ROB: Now use LookBackTimeToSnap + sfh_time instead. // o->sfh_dt[j]=g->sfh_dt[j]*UnitTime_in_years/Hubble_h; o->sfh_DiskMass[j]=g->sfh_DiskMass[j]; o->sfh_BulgeMass[j]=g->sfh_BulgeMass[j]; o->sfh_ICM[j]=g->sfh_ICM[j]; o->sfh_MetalsDiskMass[j]=g->sfh_MetalsDiskMass[j]; o->sfh_MetalsBulgeMass[j]=g->sfh_MetalsBulgeMass[j]; o->sfh_MetalsICM[j]=g->sfh_MetalsICM[j]; //#ifdef DETAILED_METALS_AND_MASS_RETURN #ifdef INDIVIDUAL_ELEMENTS o->sfh_ElementsDiskMass[j]=g->sfh_ElementsDiskMass[j]; o->sfh_ElementsBulgeMass[j]=g->sfh_ElementsBulgeMass[j]; o->sfh_ElementsICM[j]=g->sfh_ElementsICM[j]; #endif //#endif #ifdef TRACK_BURST o->sfh_BurstMass[j]=g->sfh_BurstMass[j]; #endif #else // NORMALIZEDDB sfh_bin[j].sfh_DiskMass = g->sfh_DiskMass[j]; sfh_bin[j].sfh_BulgeMass = g->sfh_BulgeMass[j]; sfh_bin[j].sfh_ICM = g->sfh_ICM[j]; sfh_bin[j].sfh_MetalsDiskMass = g->sfh_MetalsDiskMass[j]; sfh_bin[j].sfh_MetalsBulgeMass = g->sfh_MetalsBulgeMass[j]; sfh_bin[j].sfh_MetalsICM = g->sfh_MetalsICM[j]; sfh_bin[j].sfh_ibin = j; sfh_bin[j].snapnum = g->SnapNum; sfh_bin[j].GalID = -1; // TODO must be reset #endif // NORMALIZEDDB } //Set all non-used array elements to zero: // important if we want to read files in database that all values are valid SQLServer floats for (j=o->sfh_ibin+1;j<SFH_NBIN;j++) { #ifndef NORMALIZEDDB // o->sfh_time[j]=0.; // o->sfh_dt[j]=0.; o->sfh_DiskMass[j]=0.; o->sfh_BulgeMass[j]=0.; o->sfh_ICM[j]=0.; o->sfh_MetalsDiskMass[j]=metals_init(); o->sfh_MetalsBulgeMass[j]=metals_init(); o->sfh_MetalsICM[j]=metals_init(); #ifdef INDIVIDUAL_ELEMENTS o->sfh_ElementsDiskMass[j]=elements_init(); o->sfh_ElementsBulgeMass[j]=elements_init(); o->sfh_ElementsICM[j]=elements_init(); #endif #ifdef TRACK_BURST o->sfh_BurstMass[j]=0.; #endif #else sfh_bin[j].sfh_DiskMass=0; sfh_bin[j].sfh_BulgeMass=0; sfh_bin[j].sfh_ICM=0; sfh_bin[j].sfh_ibin = 0; sfh_bin[j].snapnum = g->SnapNum; // TODO other elements not important, are not being written anyway. Or are they used elsewhere? #endif } #endif //STAR_FORMATION_HISTORY #ifdef INDIVIDUAL_ELEMENTS /*for (j=0;j<ELEMENT_NUM;j++) { o->DiskMass_elements[j]=g->DiskMass_elements[j]; o->BulgeMass_elements[j]=g->BulgeMass_elements[j]; o->ColdGas_elements[j]=g->ColdGas_elements[j]; o->HotGas_elements[j]=g->HotGas_elements[j]; o->EjectedMass_elements[j]=g->EjectedMass_elements[j]; o->ICM_elements[j]=g->ICM_elements[j]; }*/ /*o->DiskMass_elements = CORRECTDBFLOAT(g->DiskMass_elements); o->BulgeMass_elements = CORRECTDBFLOAT(g->BulgeMass_elements); o->ColdGas_elements = CORRECTDBFLOAT(g->ColdGas_elements); o->HotGas_elements = CORRECTDBFLOAT(g->HotGas_elements); o->ICM_elements = CORRECTDBFLOAT(g->ICM_elements);*/ o->DiskMass_elements = g->DiskMass_elements; o->BulgeMass_elements = g->BulgeMass_elements; o->ColdGas_elements = g->ColdGas_elements; o->HotGas_elements = g->HotGas_elements; o->EjectedMass_elements = g->EjectedMass_elements; o->ICM_elements = g->ICM_elements; #endif o->PrimordialAccretionRate = CORRECTDBFLOAT(g->PrimordialAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->CoolingRate = CORRECTDBFLOAT(g->CoolingRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->CoolingRate_beforeAGN = CORRECTDBFLOAT(g->CoolingRate_beforeAGN * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); //NOTE: in Msun/yr #ifdef SAVE_MEMORY o->Sfr = CORRECTDBFLOAT(g->Sfr * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); #ifdef H2_AND_RINGS for(j=0; j<RNUM; j++) o->Sfrr[j] = g->Sfrr[j] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; #endif #else o->Sfr = CORRECTDBFLOAT(g->Sfr[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); #endif #endif //NO_PROPS_OUTPUTS //MAGNITUDES #ifdef COMPUTE_SPECPHOT_PROPERTIES #ifdef POST_PROCESS_MAGS /* int N_vespa_files=29, N_vespa_AgeBins=16; double vespa_age[17]={0.000125893, 0.02000, 0.03000, 0.04800, 0.07400, 0.11500, 0.17700, 0.27500, 0.42500, 0.65800, 1.02000, 1.57000, 2.44000, 3.78000, 5.84000, 9.04000, 14.0000}; int vespa_sfh_IDs[29]={0, 1, 12, 16, 2, 22, 23, 27, 29, 36, 42, 44, 50, 53, 54, 55, 56, 57, 61, 62, 63, 64, 65, 71, 81, 82, 90, 94, 99}; double vespa_sfh[N_vespa_AgeBins], vespa_metal[N_vespa_AgeBins], dumb[6]; int ii, jj, kk; char buf[1000], sbuf[1000]; FILE *fa; for (ii=1;ii<N_vespa_files;ii++) { sprintf(buf, "./devel/vespa_sfh/disc_good_%d.txt", vespa_sfh_IDs[ii]); if(!(fa = fopen(buf, "r"))) { char sbuf[1000]; sprintf(sbuf, "can't open file `%s'\n", buf); terminate(sbuf); } for(jj=0;jj<6;jj++) fgets(buf, 300, fa); //read vespa SFH and metallicities for (jj=0;jj<N_vespa_AgeBins;jj++) { vespa_sfh[jj]=0.; vespa_metal[jj]=0.; fscanf(fa,"%lg %lg %lg %lg %lg %lg %lg %lg\n", &dumb[0], &dumb[1], &vespa_sfh[jj], &dumb[2], &vespa_metal[jj], &dumb[3], &dumb[4], &dumb[5]); } fclose(fa); for (jj=0;jj<SFH_NBIN;jj++) { if(jj<N_vespa_AgeBins) { o->sfh_time[jj]=(vespa_age[jj]+vespa_age[jj+1])/2.*1.e9; o->sfh_dt[jj]=(vespa_age[jj+1]-vespa_age[jj])/2.*1.e9; o->sfh_DiskMass[jj]=vespa_sfh[jj]; o->sfh_BulgeMass[jj]=0.; o->sfh_MetalsDiskMass[jj]=vespa_metal[jj]*o->sfh_DiskMass[jj]; o->sfh_MetalsBulgeMass[jj]=metals_init(); } else { o->sfh_time[jj]=0.; o->sfh_dt[jj]=0.; o->sfh_DiskMass[jj]=0.; o->sfh_BulgeMass[jj]=0.; o->sfh_MetalsDiskMass[jj]=metals_init(); o->sfh_MetalsBulgeMass[jj]=metals_init(); } } post_process_spec_mags(o); sprintf(buf, "./devel/vespa_sfh/output_spectradisc_good_%d.txt", vespa_sfh_IDs[ii]); if(!(fa = fopen(buf, "w"))) { char sbuf[1000]; sprintf(sbuf, "can't open file `%s'\n", buf); terminate(sbuf); } for(jj=0;jj<NMAG;jj++) fprintf(fa,"%e\n",o->Mag[jj]); fclose(fa); exit(0); } */ //Convert recorded star formation histories into mags #ifdef NORMALIZEDDB post_process_spec_mags(o, &(sfh_bin[0])); #else post_process_spec_mags(o); #endif #else //ndef POST_PROCESS_MAGS #ifdef OUTPUT_REST_MAGS // Luminosities are converted into Mags in various bands for(j = 0; j < NMAG; j++) { //o->Mag[j] = lum_to_mag(g->Lum[j][n]); -> DONE ON TOP FOR LIGHT_OUTPUT AS WELL o->MagBulge[j] = lum_to_mag(g->LumBulge[j][n]); o->MagDust[j] = lum_to_mag(g->LumDust[j][n]); #ifdef ICL o->MagICL[j] = lum_to_mag(g->ICLLum[j][n]); #endif } #if defined(READXFRAC) || defined(WITHRADIATIVETRANSFER) o->Xfrac3d = g->Xfrac3d; #endif #endif //OUTPUT_REST_MAGS #ifdef OUTPUT_OBS_MAGS #ifdef COMPUTE_OBS_MAGS // Luminosities in various bands for(j = 0; j < NMAG; j++) { o->ObsMag[j] = lum_to_mag(g->ObsLum[j][n]); o->ObsMagBulge[j] = lum_to_mag(g->ObsLumBulge[j][n]); o->ObsMagDust[j] = lum_to_mag(g->ObsLumDust[j][n]); #ifdef ICL o->ObsMagICL[j] = lum_to_mag(g->ObsICL[j][n]); #endif #ifdef OUTPUT_MOMAF_INPUTS o->dObsMag[j] = lum_to_mag(g->dObsLum[j][n]); o->dObsMagBulge[j] = lum_to_mag(g->dObsLumBulge[j][n]); o->dObsMagDust[j] = lum_to_mag(g->dObsLumDust[j][n]); #ifdef ICL o->dObsMagICL[j] = lum_to_mag(g->dObsICL[j][n]); #endif #endif } #endif //COMPUTE_OBS_MAGS #endif //OUTPUT_OBS_MAGS #endif //ndef POST_PROCESS_MAGS #endif //COMPUTE_SPECPHOT_PROPERTIES #ifndef NO_PROPS_OUTPUTS if((g->DiskMass+g->BulgeMass)> 0.0) { o->MassWeightAge = g->MassWeightAge[n] / (g->DiskMass+g->BulgeMass); o->MassWeightAge = o->MassWeightAge / 1000. * UnitTime_in_Megayears / Hubble_h; //Age in Gyr } else o->MassWeightAge = 0.; #endif #ifdef FIX_OUTPUT_UNITS fix_units_for_ouput(o); #endif #endif //ndef LIGHT_OUTPUT // DEBUG // printf(" EXIT sfh_bin %d %f\n",sfh_bin,sfh_bin[0].sfh_DiskMass); }
/* Note: halonr is here the FOF-background subhalo (i.e. main halo) */ void evolve_galaxies(int halonr, int ngal, int treenr, int cenngal) { int p, q, nstep, centralgal, merger_centralgal, currenthalo, prevgal, start, i; double infallingGas, deltaT, Zcurr; double time, previoustime, newtime; double AGNaccreted, t_Edd; #ifdef STAR_FORMATION_HISTORY double age_in_years; #endif // Eddington time in code units // code units are UnitTime_in_s/Hubble_h t_Edd=1.42e16*Hubble_h/UnitTime_in_s; //previoustime = NumToTime(Gal[0].SnapNum); previoustime = NumToTime(Halo[halonr].SnapNum-1); newtime = NumToTime(Halo[halonr].SnapNum); /* Time between snapshots */ deltaT = previoustime - newtime; /* Redshift of current Snapnum */ Zcurr = ZZ[Halo[halonr].SnapNum]; centralgal = Gal[0].CentralGal; for (p =0;p<ngal;p++) mass_checks("Evolve_galaxies #0",p); //print_galaxy("\n\ncheck1", centralgal, halonr); if(Gal[centralgal].Type != 0 || Gal[centralgal].HaloNr != halonr) terminate("Something wrong here ..... \n"); /* Update all galaxies to same star-formation history time-bins. * Needed in case some galaxy has skipped a snapshot. */ #ifdef STAR_FORMATION_HISTORY age_in_years=(Age[0]-previoustime)*UnitTime_in_years/Hubble_h; //ROB: age_in_years is in units of "real years"! nstep=0; for (p=0; p<ngal; p++) sfh_update_bins(p,Halo[halonr].SnapNum-1,nstep,age_in_years); #endif /* Handle the transfer of mass between satellites and central galaxies */ deal_with_satellites(centralgal, ngal); /* Delete inconsequential galaxies */ for (p =0;p<ngal;p++) if (Gal[p].Type ==2 && Gal[p].ColdGas+Gal[p].DiskMass+Gal[p].BulgeMass <1.e-8) Gal[p].Type = 3; else mass_checks("Evolve_galaxies #0.1",p); /* Calculate how much hot gas needs to be accreted to give the correct baryon fraction * in the main halo. This is the universal fraction, less any reduction due to reionization. */ infallingGas = infall_recipe(centralgal, ngal, Zcurr); Gal[centralgal].PrimordialAccretionRate=infallingGas/deltaT; /* All the physics are computed in a number of intervals between snapshots * equal to STEPS */ for (nstep = 0; nstep < STEPS; nstep++) { /* time to present of the current step */ time = previoustime - (nstep + 0.5) * (deltaT / STEPS); /* Update all galaxies to the star-formation history time-bins of current step*/ #ifdef STAR_FORMATION_HISTORY age_in_years=(Age[0]-time)*UnitTime_in_years/Hubble_h; for (p=0; p<ngal; p++) sfh_update_bins(p,Halo[halonr].SnapNum-1,nstep,age_in_years); #endif /* Infall onto central galaxy only, if required to make up a baryon deficit */ #ifndef GUO10 #ifndef GUO13 if (infallingGas > 0.) #endif #endif add_infall_to_hot(centralgal, infallingGas / STEPS); mass_checks("Evolve_galaxies #0.5",centralgal); for (p = 0; p < ngal; p++) { /* don't treat galaxies that have already merged */ if(Gal[p].Type == 3) continue; mass_checks("Evolve_galaxies #1",p); if (Gal[p].Type == 0 || Gal[p].Type == 1) { reincorporate_gas(p, deltaT / STEPS); /* determine cooling gas given halo properties and add it to the cold phase*/ mass_checks("Evolve_galaxies #1.5",p); compute_cooling(p, deltaT / STEPS, ngal); } } //this must be separated as now satellite AGN can heat central galaxies //therefore the AGN from all satellites must be computed, in a loop inside this function, //before gas is cooled into central galaxies (only suppress cooling, the gas is not actually heated) if(AGNRadioModeModel != 5) do_AGN_heating(deltaT / STEPS, ngal); for (p = 0; p < ngal; p++) { cool_gas_onto_galaxy(p, deltaT / STEPS); mass_checks("Evolve_galaxies #2",p); starformation(p, centralgal, time, deltaT / STEPS, nstep); mass_checks("Evolve_galaxies #3",p); //print_galaxy("check3", centralgal, halonr); } /* Check for merger events */ for(p = 0; p < ngal; p++) { if(Gal[p].Type == 2 || (Gal[p].Type == 1 && Gal[p].MergeOn == 1)) /* satellite galaxy */ { Gal[p].MergTime -= deltaT / STEPS; if(Gal[p].MergTime < 0.0) { NumMergers++; if(Gal[p].Type == 1) for(q = 0; q < ngal; q++) if(Gal[q].Type == 2 && Gal[p].CentralGal == p) Gal[q].CentralGal = cenngal; if(Gal[p].Type == 2) merger_centralgal = Gal[p].CentralGal; else merger_centralgal = cenngal; mass_checks("Evolve_galaxies #4",p); mass_checks("Evolve_galaxies #4",merger_centralgal); mass_checks("Evolve_galaxies #4",centralgal); deal_with_galaxy_merger(p, merger_centralgal, centralgal, time, deltaT, nstep); mass_checks("Evolve_galaxies #5",p); mass_checks("Evolve_galaxies #5",merger_centralgal); mass_checks("Evolve_galaxies #5",centralgal); } } }//loop on all galaxies to detect mergers #ifdef DETAILED_METALS_AND_MASS_RETURN //DELAYED ENRICHMENT AND MASS RETURN + FEEDBACK: No fixed yield or recycling fraction anymore. FB synced with enrichment for (p = 0; p < ngal; p++) update_yields_and_return_mass(p, centralgal, deltaT/STEPS, nstep); #endif }/* end move forward in interval STEPS */ for(p = 0; p < ngal; p++) { if(Gal[p].Type == 2) { #ifndef UPDATETYPETWO int jj; float tmppos; for(jj = 0; jj < 3; jj++) { tmppos = wrap(Gal[p].DistanceToCentralGal[jj],BoxSize); tmppos *= 2.*sqrt(Gal[p].MergTime/Gal[p].OriMergTime); Gal[p].Pos[jj] = Gal[p].MergCentralPos[jj] + tmppos; if(Gal[p].Pos[jj] < 0) Gal[p].Pos[jj] = BoxSize + Gal[p].Pos[jj]; if(Gal[p].Pos[jj] > BoxSize) Gal[p].Pos[jj] = Gal[p].Pos[jj] - BoxSize; } #endif /* Disruption of type 2 galaxies. Type 1 galaxies are not disrupted since usually * bayonic component is more compact than dark matter.*/ if(DisruptionModel==0) disrupt(p); } } for (p =0;p<ngal;p++) mass_checks("Evolve_galaxies #6",p); #ifdef COMPUTE_SPECPHOT_PROPERTIES #ifndef POST_PROCESS_MAGS int n; /* If this is an output snapshot apply the dust model to each galaxy */ for(n = 0; n < NOUT; n++) { if(Halo[halonr].SnapNum == ListOutputSnaps[n]) { for(p = 0; p < ngal; p++) dust_model(p, n, halonr); break; } } #endif //POST_PROCESS_MAGS #endif //COMPUTE_SPECPHOT_PROPERTIES /* now save the galaxies of all the progenitors (and free the associated storage) */ int prog = Halo[halonr].FirstProgenitor; while(prog >= 0) { int currentgal; for(i = 0, currentgal = HaloAux[prog].FirstGalaxy; i < HaloAux[prog].NGalaxies; i++) { int nextgal = HaloGal[currentgal].NextGalaxy; /* this will write this galaxy to an output file and free the storage associate with it */ output_galaxy(treenr, HaloGal[currentgal].HeapIndex); currentgal = nextgal; } prog = Halo[prog].NextProgenitor; } for(p = 0, prevgal = -1, currenthalo = -1, centralgal = -1, start = NGalTree; p < ngal; p++) { if(Gal[p].HaloNr != currenthalo) { currenthalo = Gal[p].HaloNr; HaloAux[currenthalo].FirstGalaxy = -1; HaloAux[currenthalo].NGalaxies = 0; } mass_checks("Evolve_galaxies #7",p); if(Gal[p].Type != 3) { if(NHaloGal >= MaxHaloGal) { int oldmax = MaxHaloGal; AllocValue_MaxHaloGal *= ALLOC_INCREASE_FACTOR; MaxHaloGal = AllocValue_MaxHaloGal; if(MaxHaloGal<NHaloGal+1) MaxHaloGal=NHaloGal+1; HaloGal = myrealloc_movable(HaloGal, sizeof(struct GALAXY) * MaxHaloGal); HaloGalHeap = myrealloc_movable(HaloGalHeap, sizeof(int) * MaxHaloGal); for(i = oldmax; i < MaxHaloGal; i++) HaloGalHeap[i] = i; } Gal[p].SnapNum = Halo[currenthalo].SnapNum; #ifndef GUO10 #ifdef UPDATETYPETWO update_type_two_coordinate_and_velocity(treenr, p, Gal[0].CentralGal); #endif #endif /* when galaxies are outputed, the slot is filled with the * last galaxy in the heap. New galaxies always take the last spot */ int nextgal = HaloGalHeap[NHaloGal]; HaloGal[nextgal] = Gal[p]; HaloGal[nextgal].HeapIndex = NHaloGal; if(HaloAux[currenthalo].FirstGalaxy < 0) HaloAux[currenthalo].FirstGalaxy = nextgal; if(prevgal >= 0) HaloGal[prevgal].NextGalaxy = nextgal; prevgal = nextgal; HaloAux[currenthalo].NGalaxies++; NHaloGal++; #ifdef GALAXYTREE if(NGalTree >= MaxGalTree) { AllocValue_MaxGalTree *= ALLOC_INCREASE_FACTOR; MaxGalTree = AllocValue_MaxGalTree; if(MaxGalTree<NGalTree+1) MaxGalTree=NGalTree+1; GalTree = myrealloc_movable(GalTree, sizeof(struct galaxy_tree_data) * MaxGalTree); } HaloGal[nextgal].GalTreeIndex = NGalTree; memset(&GalTree[NGalTree], 0, sizeof(struct galaxy_tree_data)); GalTree[NGalTree].HaloGalIndex = nextgal; GalTree[NGalTree].SnapNum = Halo[currenthalo].SnapNum; GalTree[NGalTree].NextProgGal = -1; GalTree[NGalTree].DescendantGal = -1; GalTree[NGalTree].FirstProgGal = Gal[p].FirstProgGal; if(Gal[p].Type == 0) centralgal = NGalTree; NGalTree++; #endif } } #ifdef GALAXYTREE for(p = start; p < NGalTree; p++) { if(centralgal < 0) terminate("centralgal < 0"); GalTree[p].FOFCentralGal = centralgal; } #endif report_memory_usage(&HighMark, "evolve_galaxies"); }
void sfh_update_bins(int p, int snap, int step, double time) { /* Adds new bins as required. * Then merges bins whenever you have three or more of the same size. * Assumes that time counts from zero at the big bang. */ int i, j; // loop index int SFH_ibin; //desired ibin (i.e. bin in question in for loop below) SFH_ibin=0; Gal[p].sfh_age=time; //t=time/SFH_TIME_INTERVAL; //ibin=Gal[p].sfh_ibin; for(i=0;i<SFH_NBIN;i++) if(SFH_Nbins[snap][step][i]>0) //i.e. If bin is active... SFH_ibin=i; //Assign with 'bin in question' if (Gal[p].sfh_ibin == 0) //i.e. If highest active bin is bin 0... { for(i=0;i<=SFH_ibin;i++) { Gal[p].sfh_t[i]=SFH_t[snap][step][i]; Gal[p].sfh_Nbins[i]=SFH_Nbins[snap][step][i]; } Gal[p].sfh_ibin=SFH_ibin; } else //i.e. If highest active bin is > bin 0... { i=0; while(i<=SFH_ibin) //Up to 'bin in question'... { if(i<=Gal[p].sfh_ibin) //...until highest active bin is reached... { if(Gal[p].sfh_Nbins[i]!= SFH_Nbins[snap][step][i]) //...and until bin has grown to required size. { // Merge bins i and i+1 Gal[p].sfh_Nbins[i]+=Gal[p].sfh_Nbins[i+1]; Gal[p].sfh_t[i]=Gal[p].sfh_t[i+1]; Gal[p].sfh_DiskMass[i]+=Gal[p].sfh_DiskMass[i+1]; Gal[p].sfh_BulgeMass[i]+=Gal[p].sfh_BulgeMass[i+1]; Gal[p].sfh_ICM[i]+=Gal[p].sfh_ICM[i+1]; Gal[p].sfh_MetalsDiskMass[i]=metals_add(Gal[p].sfh_MetalsDiskMass[i],Gal[p].sfh_MetalsDiskMass[i+1],1.); Gal[p].sfh_MetalsBulgeMass[i]=metals_add(Gal[p].sfh_MetalsBulgeMass[i],Gal[p].sfh_MetalsBulgeMass[i+1],1.); Gal[p].sfh_MetalsICM[i]= metals_add(Gal[p].sfh_MetalsICM[i],Gal[p].sfh_MetalsICM[i+1],1.); #ifdef INDIVIDUAL_ELEMENTS Gal[p].sfh_ElementsDiskMass[i] = elements_add(Gal[p].sfh_ElementsDiskMass[i],Gal[p].sfh_ElementsDiskMass[i+1],1.); Gal[p].sfh_ElementsBulgeMass[i] = elements_add(Gal[p].sfh_ElementsBulgeMass[i],Gal[p].sfh_ElementsBulgeMass[i+1],1.); Gal[p].sfh_ElementsICM[i] = elements_add(Gal[p].sfh_ElementsICM[i],Gal[p].sfh_ElementsICM[i+1],1.); #endif #ifdef TRACK_BURST Gal[p].sfh_BurstMass[i]+=Gal[p].sfh_BurstMass[i+1]; #endif // Relabel all the other bins for(j=i+1;j<Gal[p].sfh_ibin;j++) { Gal[p].sfh_Nbins[j]=Gal[p].sfh_Nbins[j+1]; Gal[p].sfh_t[j]=Gal[p].sfh_t[j+1]; Gal[p].sfh_DiskMass[j]=Gal[p].sfh_DiskMass[j+1]; Gal[p].sfh_BulgeMass[j]=Gal[p].sfh_BulgeMass[j+1]; Gal[p].sfh_ICM[j]=Gal[p].sfh_ICM[j+1]; Gal[p].sfh_MetalsDiskMass[j]=Gal[p].sfh_MetalsDiskMass[j+1]; Gal[p].sfh_MetalsBulgeMass[j]=Gal[p].sfh_MetalsBulgeMass[j+1]; Gal[p].sfh_MetalsICM[j]=Gal[p].sfh_MetalsICM[j+1]; #ifdef INDIVIDUAL_ELEMENTS Gal[p].sfh_ElementsDiskMass[j]=Gal[p].sfh_ElementsDiskMass[j+1]; Gal[p].sfh_ElementsBulgeMass[j]=Gal[p].sfh_ElementsBulgeMass[j+1]; Gal[p].sfh_ElementsICM[j]=Gal[p].sfh_ElementsICM[j+1]; #endif #ifdef TRACK_BURST Gal[p].sfh_BurstMass[j]=Gal[p].sfh_BurstMass[j+1]; #endif } //set last bin to zero Gal[p].sfh_flag[j]=0; Gal[p].sfh_Nbins[j]=0; Gal[p].sfh_t[j]=0.; Gal[p].sfh_DiskMass[j]=0.; Gal[p].sfh_BulgeMass[j]=0.; Gal[p].sfh_ICM[j]=0.; Gal[p].sfh_MetalsDiskMass[j]=metals_init(); Gal[p].sfh_MetalsBulgeMass[j]=metals_init(); Gal[p].sfh_MetalsICM[j]=metals_init(); #ifdef INDIVIDUAL_ELEMENTS Gal[p].sfh_ElementsDiskMass[j]=elements_init(); Gal[p].sfh_ElementsBulgeMass[j]=elements_init(); Gal[p].sfh_ElementsICM[j]=elements_init(); #endif #ifdef TRACK_BURST Gal[p].sfh_BurstMass[j]=0.; #endif Gal[p].sfh_ibin=j-1; /* If there are no more time bins in the galaxy to merge and * the last bin still doesn't have the required size * re-size it according to the reference structure SFH */ if(Gal[p].sfh_Nbins[i+1]==0) { Gal[p].sfh_Nbins[i]=SFH_Nbins[snap][step][i]; Gal[p].sfh_t[i]=SFH_t[snap][step][i]; i+=1; } } else i+=1; } else { //no more bins available in the galaxy, fill the rest times from SFH array for(j=i;j<=SFH_ibin;j++) { Gal[p].sfh_Nbins[j]=SFH_Nbins[snap][step][j]; Gal[p].sfh_t[j]=SFH_t[snap][step][j]; Gal[p].sfh_DiskMass[j]=0.; Gal[p].sfh_BulgeMass[j]=0.; Gal[p].sfh_ICM[j]=0.; Gal[p].sfh_MetalsDiskMass[j]=metals_init(); Gal[p].sfh_MetalsBulgeMass[j]=metals_init(); Gal[p].sfh_MetalsICM[j]=metals_init(); #ifdef INDIVIDUAL_ELEMENTS Gal[p].sfh_ElementsDiskMass[j]=elements_init(); Gal[p].sfh_ElementsBulgeMass[j]=elements_init(); Gal[p].sfh_ElementsICM[j]=elements_init(); #endif #ifdef TRACK_BURST Gal[p].sfh_BurstMass[j]=0.; #endif Gal[p].sfh_ibin=j; } i=j; } }//end while }//end else for(i=0;i<SFH_NBIN;i++) { if(i==0) Gal[p].sfh_dt[i]=NumToTime(0)-Gal[p].sfh_t[i]; else Gal[p].sfh_dt[i]=Gal[p].sfh_t[i-1]-Gal[p].sfh_t[i]; } }
void create_sfh_bins() { double previoustime, newtime, deltaT, time; int snap, step, sfh_ibin, i, j, sfh_Nbins[SFH_NBIN]; int ibin_max=0; double sfh_t[SFH_NBIN]; for(snap = 0; snap < MAXSNAPS; snap++) { for(step=0;step < STEPS;step++) { for(j=0;j < SFH_NBIN;j++) { SFH_t[snap][step][j]=0; SFH_dt[snap][step][j]=0; SFH_ibin[snap][step]=0; SFH_Nbins[snap][step][j] = 0; } } } for(i=0;i<SFH_NBIN;i++) { sfh_Nbins[i]=0; sfh_t[i]=0.; } sfh_ibin=0; //for(snap=0;snap<(LastDarkMatterSnapShot+1)-1;snap++) { for(snap=0;snap<(LastDarkMatterSnapShot+1);snap++) { previoustime = NumToTime(snap); newtime = NumToTime(snap+1); deltaT = previoustime - newtime; for(step=0;step<STEPS;step++) { int ibin; int flag_merged_bins; // Boolean used to check whether have merged bins int dt_merge; // Size of bins that we are checking for merging int n_merge; // Number of bins of this size time = previoustime - (step + 1.0) * (deltaT / STEPS); ibin=sfh_ibin; //printf("sna=%d step=%d step time=%f time low=%f\n", // snap,step,(previoustime - (step + 0.5) * (deltaT / STEPS))*UnitTime_in_years/Hubble_h/1.e9, // (time)*UnitTime_in_years/Hubble_h/1.e9); //Add one extra bin if(snap==0 && step==0) { sfh_t[0]=time; sfh_Nbins[0]=1; } else { ibin+=1; if(ibin==SFH_NBIN) terminate("sfh_update_bins: too many bins required\n"); ibin_max=max(ibin_max,ibin); sfh_Nbins[ibin]=1; sfh_t[ibin]=time; } /* Now merge bins where we have SFH_NMERGE bins of the same size. * Need to do this iteratively. */ flag_merged_bins=1; while(flag_merged_bins) { flag_merged_bins=0; dt_merge=sfh_Nbins[0]; i=0; // Will have checked all bins once dt_merge drops to zero while(!flag_merged_bins && dt_merge>0) { // Count number of bins of this size n_merge=0; // The i=i below is to suppress a warning message for(i=i;sfh_Nbins[i]==dt_merge;i++) n_merge+=1; /* If fewer than SFH_NMERGE bins then do nothing * (SFH_NMERGE+1 bins if dt_merge=1) * else exit loop and flag for merging */ if (n_merge<SFH_NMERGE || (n_merge==SFH_NMERGE && dt_merge==1)) { /* In new version of the code, treat smallest bins just like any others */ //if (n_merge<SFH_NMERGE) { dt_merge/=2; n_merge=0; } else { flag_merged_bins=1; i=i-n_merge; } } /* At this point, if flag_merged_bins is set then * we have to merge SFH_NMERGE bins into SFH_NMERGE-1. */ if(flag_merged_bins) { /* Merge bins i and i+1 */ sfh_Nbins[i]*=2; sfh_t[i]=sfh_t[i+1]; /* Relabel all the other bins */ for(i=i+1;i<ibin;i++) { sfh_Nbins[i]=sfh_Nbins[i+1]; sfh_t[i]=sfh_t[i+1]; } sfh_Nbins[i]=0; sfh_t[i]=0.; ibin=i-1; } } // End loop over bin merging sfh_ibin=ibin; //if(step==19) //printf("snap=%d\n",snap+1); for(j=0;j<=sfh_ibin;j++) { SFH_t[snap][step][j]=sfh_t[j]; //Time to present at the low-z edge of the bin (code units) SFH_Nbins[snap][step][j]=sfh_Nbins[j];//Number of bins merged in each bin (only useful for the merging algorithm) if(j==0) SFH_dt[snap][step][j]=NumToTime(0)-sfh_t[j];//Time width of the bin (code units) else SFH_dt[snap][step][j]=sfh_t[j-1]-sfh_t[j];//Time width of the bin (code units) } SFH_ibin[snap][step]=sfh_ibin; //Last active bin }//end loop on steps }//end loop on snaps //exit(0); #ifdef PARALLEL if(ThisTask==0) #endif printf("Max number of SFH bins used = %d\n",ibin_max+1); }
/* Note: halonr is here the FOF-background subhalo (i.e. main halo) */ void evolve_galaxies(int halonr, int ngal, int treenr, int cenngal) { int jj, p, q, nstep, centralgal, merger_centralgal, currenthalo, prevgal, start, i; double infallingGas, coolingGas, deltaT, Zcurr; double time, previoustime, newtime; double AGNaccreted, t_Edd; #ifdef STAR_FORMATION_HISTORY double age_in_years; #endif #ifdef HT09_DISRUPTION double CentralRadius, CentralMass, SatelliteRadius, SatelliteMass; #endif // Eddington time in code units // Bizarrely, code units are UnitTime_in_s/Hubble_h t_Edd=1.42e16*Hubble_h/UnitTime_in_s; //previoustime = NumToTime(Gal[0].SnapNum); previoustime = NumToTime(Halo[halonr].SnapNum-1); newtime = NumToTime(Halo[halonr].SnapNum); /* Time between snapshots */ deltaT = previoustime - newtime; /* Redshift of current Snapnum */ Zcurr = ZZ[Halo[halonr].SnapNum]; //if(halonr == 83) // for(p=0;p<ngal;p++) // printf("check halonr=%d id=%d type=%d\n", halonr, p,Gal[p].Type); centralgal = Gal[0].CentralGal; for (p =0;p<ngal;p++) mass_checks("Evolve_galaxies #0",p); if(Gal[centralgal].Type != 0 || Gal[centralgal].HaloNr != halonr) terminate("Something wrong here ..... \n"); /* Update all galaxies to same star-formation history time-bins. * Needed in case some galaxy has skipped a snapshot. */ #ifdef STAR_FORMATION_HISTORY age_in_years=(Age[0]-previoustime)*UnitTime_in_years/Hubble_h; //ROB: age_in_years is in units of "real years"! nstep=0; for (p=0; p<ngal; p++) sfh_update_bins(p,Halo[halonr].SnapNum-1,nstep,age_in_years); #endif //if(halonr == 84) // print_galaxy("check00", centralgal, halonr); //for(p=0;p<ngal;p++) // printf("prog=%d\n",Halo[halonr].FirstProgenitor); /* Handle the transfer of mass between satellites and central galaxies */ deal_with_satellites(centralgal, ngal); /* Delete inconsequential galaxies */ for (p =0;p<ngal;p++) if (Gal[p].Type ==2 && Gal[p].ColdGas+Gal[p].DiskMass+Gal[p].BulgeMass <1.e-8) Gal[p].Type = 3; else mass_checks("Evolve_galaxies #0.1",p); /* Calculate how much hot gas needs to be accreted to give the correct baryon fraction * in the main halo. This is the universal fraction, less any reduction due to reionization. */ infallingGas = infall_recipe(centralgal, ngal, Zcurr); Gal[centralgal].PrimordialAccretionRate=infallingGas/deltaT; //if(halonr > 35 && halonr < 40) // print_galaxy("check02", centralgal, halonr); /* All the physics are computed in a number of intervals between snapshots * equal to STEPS */ for (nstep = 0; nstep < STEPS; nstep++) { //printf("step=%d\n",nstep); /* time to present of the current step */ time = previoustime - (nstep + 0.5) * (deltaT / STEPS); /* Update all galaxies to the star-formation history time-bins of current step*/ #ifdef STAR_FORMATION_HISTORY age_in_years=(Age[0]-time)*UnitTime_in_years/Hubble_h; for (p=0; p<ngal; p++) sfh_update_bins(p,Halo[halonr].SnapNum-1,nstep,age_in_years); #endif //if(halonr > 35 && halonr < 40) // print_galaxy("check02.1", centralgal, halonr); /* Infall onto central galaxy only, if required to make up a baryon deficit */ #ifndef GUO13 #ifndef GUO10 if (infallingGas > 0.) #endif #endif add_infall_to_hot(centralgal, infallingGas / STEPS); //if(halonr == 84) // print_galaxy("check02.5", centralgal, halonr); mass_checks("Evolve_galaxies #0.5",centralgal); for (p = 0; p < ngal; p++) { //if((halonr > 28 && halonr < 32) || Gal[p].HaloNr==52) //if(Gal[p].SnapNum==31 || (halonr > 28 && halonr < 31)) // if(halonr ==140) // print_galaxy("check03", p, halonr); /* don't treat galaxies that have already merged */ if(Gal[p].Type == 3) continue; mass_checks("Evolve_galaxies #1",p); if (Gal[p].Type == 0 || Gal[p].Type == 1) { if((ReIncorporationRecipe == 0 && Gal[p].Type==0) || ReIncorporationRecipe > 0) reincorporate_gas(p, deltaT / STEPS); //if(halonr > 28 && halonr < 31) // print_galaxy("check04", p, halonr); /* determine cooling gas given halo properties and add it to the cold phase*/ mass_checks("Evolve_galaxies #1.5",p); coolingGas = cooling_recipe(p, deltaT / STEPS); cool_gas_onto_galaxy(p, coolingGas); //if(halonr > 28 && halonr < 31) //if(halonr ==140) //print_galaxy("check05", p, halonr); } mass_checks("Evolve_galaxies #2",p); #ifdef H2_AND_RINGS gas_inflow(p, deltaT / STEPS); //if(halonr > 38 && halonr < 40) //print_galaxy("check06", p, halonr); #endif /* stars form*/ starformation(p, centralgal, time, deltaT / STEPS, nstep); //int ii; //for (ii = 0; ii < ngal; ii++) // if(halonr > 28 && halonr < 31) //if(halonr ==140) // print_galaxy("check07", ii, halonr); mass_checks("Evolve_galaxies #3",p); } //for (p = 0; p < ngal; p++) /* Check for merger events */ //if(Gal[p].Type == 1) //for(p = 0; p < -1; p++) for(p = 0; p < ngal; p++) { //if(halonr == 84) // print_galaxy("check07.01", p, halonr); #ifdef MERGE01 if(Gal[p].Type == 2 || (Gal[p].Type == 1 && Gal[p].MergeOn == 1)) /* satellite galaxy */ #else if(Gal[p].Type == 2) #endif { Gal[p].MergTime -= deltaT / STEPS; #ifdef HT09_DISRUPTION Gal[p].MergRadius -= get_deltar(p, deltaT/STEPS ); if(Gal[p].MergRadius<0.) Gal[p].MergRadius=0.; //printf("merge radius=%f detlar=%f\n",Gal[p].MergRadius, 100.*get_deltar(p, deltaT/STEPS )); disruption_code (p, time); /* a merger has occured! */ //MergRadius is tracked for type 2's subject to disruption while MergTime is tracked for type 1's // if( ( Gal[p].Type == 2 && (Gal[p].MergRadius < Gal[centralgal].StellarDiskRadius+Gal[centralgal].BulgeSize || Gal[p].BulgeMass+Gal[p].DiskMass == 0) ) // || (Gal[p].Type == 1 && Gal[p].MergTime < 0.0)) if( Gal[p].MergRadius < Gal[centralgal].StellarDiskRadius+Gal[centralgal].BulgeSize || Gal[p].BulgeMass+Gal[p].DiskMass == 0 ) //if(Gal[p].MergTime < 0.0 || Gal[p].BulgeMass+Gal[p].DiskMass == 0) #else if(Gal[p].MergTime < 0.0) #endif { NumMergers++; #ifdef MERGE01 if(Gal[p].Type == 1) for(q = 0; q < ngal; q++) if(Gal[q].Type == 2 && Gal[p].CentralGal == p) Gal[q].CentralGal = cenngal; if(Gal[p].Type == 2) merger_centralgal = Gal[p].CentralGal; else merger_centralgal = cenngal; #else merger_centralgal = Gal[p].CentralGal; #endif mass_checks("Evolve_galaxies #4",p); mass_checks("Evolve_galaxies #4",merger_centralgal); mass_checks("Evolve_galaxies #4",centralgal); //if(halonr == 140) //print_galaxy("check08", p, halonr); //if(halonr == 140) //print_galaxy("check09", merger_centralgal, halonr); deal_with_galaxy_merger(p, merger_centralgal, centralgal, time, deltaT, nstep); //if(halonr == 140) //print_galaxy("check10", p, halonr); //if(halonr == 140) //print_galaxy("check11", merger_centralgal, halonr); mass_checks("Evolve_galaxies #5",p); mass_checks("Evolve_galaxies #5",merger_centralgal); mass_checks("Evolve_galaxies #5",centralgal); } }// if(Gal[p].Type == 2) }//loop on all galaxies to detect mergers /* Cool gas onto AGN */ if (BlackHoleGrowth == 1) { for (p = 0; p < ngal; p++) { AGNaccreted=min(Gal[p].BlackHoleGas, Gal[p].BlackHoleMass*BlackHoleAccretionRate*deltaT/(STEPS*t_Edd)); if (AGNaccreted > 0.) { Gal[p].BlackHoleMass += AGNaccreted; Gal[p].BlackHoleGas -= AGNaccreted; // Instantaneous accretion rate. This will get overwritten on each mini-step but that's OK Gal[p].QuasarAccretionRate = AGNaccreted*STEPS/deltaT; } } } //DELAYED ENRICHMENT AND MASS RETURN + FEEDBACK: No fixed yield or recycling fraction anymore. FB synced with enrichment for (p = 0; p < ngal; p++) { #ifdef DETAILED_METALS_AND_MASS_RETURN update_yields_and_return_mass(p, centralgal, deltaT/STEPS, nstep); #endif } #ifdef ALL_SKY_LIGHTCONE int nr, istep, ix, iy, iz; istep = Halo[halonr].SnapNum*STEPS + nstep; Gal[p].SnapNum = Halo[halonr].SnapNum; for (p = 0; p < ngal; p++) for (nr = 0; nr < NCONES; nr++) for (ix = 0; ix < NREPLICA; ix++) for (iy = 0; iy < NREPLICA; iy++) for (iz = 0; iz < NREPLICA; iz++) inside_lightcone(p, istep, nr, ix, iy, iz); #endif }/* end move forward in interval STEPS */ /* check the bulge size*/ //checkbulgesize_main(ngal); for(p = 0; p < ngal; p++) { if(Gal[p].Type == 2) { //if(halonr == 140) //print_galaxy("check12", p, halonr); /*#ifdef UPDATETYPETWO update_type_two_coordinate_and_velocity(treenr, p, centralgal); #else*/ #ifndef UPDATETYPETWO int jj; float tmppos; for(jj = 0; jj < 3; jj++) { tmppos = wrap(Gal[p].DistanceToCentralGal[jj],BoxSize); tmppos *= (Gal[p].MergTime/Gal[p].OriMergTime); Gal[p].Pos[jj] = Gal[p].MergCentralPos[jj] + tmppos; if(Gal[p].Pos[jj] < 0) Gal[p].Pos[jj] = BoxSize + Gal[p].Pos[jj]; if(Gal[p].Pos[jj] > BoxSize) Gal[p].Pos[jj] = Gal[p].Pos[jj] - BoxSize; } #endif /* Disruption of type 2 galaxies. Type 1 galaxies are not disrupted since usually * bayonic component is more compact than dark matter.*/ #ifdef DISRUPTION //if(halonr == 84) //print_galaxy("check13", p, halonr); disrupt(p, Gal[p].CentralGal); //if(halonr == 84) //print_galaxy("check014", p, halonr); #endif } //if(halonr > 20 && halonr < 31) //if(halonr ==140) // print_galaxy("check015", p, halonr); } for (p =0;p<ngal;p++) mass_checks("Evolve_galaxies #6",p); #ifdef COMPUTE_SPECPHOT_PROPERTIES #ifndef POST_PROCESS_MAGS int n; /* If this is an output snapshot apply the dust model to each galaxy */ for(n = 0; n < NOUT; n++) { if(Halo[halonr].SnapNum == ListOutputSnaps[n]) { for(p = 0; p < ngal; p++) dust_model(p, n, halonr); break; } } #endif //POST_PROCESS_MAGS #endif //COMPUTE_SPECPHOT_PROPERTIES /* now save the galaxies of all the progenitors (and free the associated storage) */ int prog = Halo[halonr].FirstProgenitor; while(prog >= 0) { int currentgal; for(i = 0, currentgal = HaloAux[prog].FirstGalaxy; i < HaloAux[prog].NGalaxies; i++) { int nextgal = HaloGal[currentgal].NextGalaxy; /* this will write this galaxy to an output file and free the storage associate with it */ output_galaxy(treenr, HaloGal[currentgal].HeapIndex); currentgal = nextgal; } prog = Halo[prog].NextProgenitor; } for(p = 0, prevgal = -1, currenthalo = -1, centralgal = -1, start = NGalTree; p < ngal; p++) { if(Gal[p].HaloNr != currenthalo) { currenthalo = Gal[p].HaloNr; HaloAux[currenthalo].FirstGalaxy = -1; HaloAux[currenthalo].NGalaxies = 0; } mass_checks("Evolve_galaxies #7",p); /* may be wrong (what/why?) */ if(Gal[p].Type != 3) { if(NHaloGal >= MaxHaloGal) { int oldmax = MaxHaloGal; AllocValue_MaxHaloGal *= ALLOC_INCREASE_FACTOR; MaxHaloGal = AllocValue_MaxHaloGal; if(MaxHaloGal<NHaloGal+1) MaxHaloGal=NHaloGal+1; HaloGal = myrealloc_movable(HaloGal, sizeof(struct GALAXY) * MaxHaloGal); HaloGalHeap = myrealloc_movable(HaloGalHeap, sizeof(int) * MaxHaloGal); for(i = oldmax; i < MaxHaloGal; i++) HaloGalHeap[i] = i; } Gal[p].SnapNum = Halo[currenthalo].SnapNum; #ifndef GUO10 #ifdef UPDATETYPETWO update_type_two_coordinate_and_velocity(treenr, p, Gal[0].CentralGal); #endif #endif /* when galaxies are outputed, the slot is filled with the * last galaxy in the heap. New galaxies always take the last spot */ int nextgal = HaloGalHeap[NHaloGal]; HaloGal[nextgal] = Gal[p]; HaloGal[nextgal].HeapIndex = NHaloGal; if(HaloAux[currenthalo].FirstGalaxy < 0) HaloAux[currenthalo].FirstGalaxy = nextgal; if(prevgal >= 0) HaloGal[prevgal].NextGalaxy = nextgal; prevgal = nextgal; HaloAux[currenthalo].NGalaxies++; NHaloGal++; #ifdef GALAXYTREE if(NGalTree >= MaxGalTree) { AllocValue_MaxGalTree *= ALLOC_INCREASE_FACTOR; MaxGalTree = AllocValue_MaxGalTree; if(MaxGalTree<NGalTree+1) MaxGalTree=NGalTree+1; GalTree = myrealloc_movable(GalTree, sizeof(struct galaxy_tree_data) * MaxGalTree); } HaloGal[nextgal].GalTreeIndex = NGalTree; memset(&GalTree[NGalTree], 0, sizeof(struct galaxy_tree_data)); GalTree[NGalTree].HaloGalIndex = nextgal; GalTree[NGalTree].SnapNum = Halo[currenthalo].SnapNum; GalTree[NGalTree].NextProgGal = -1; GalTree[NGalTree].DescendantGal = -1; GalTree[NGalTree].FirstProgGal = Gal[p].FirstProgGal; if(Gal[p].Type == 0) centralgal = NGalTree; NGalTree++; #endif } } #ifdef GALAXYTREE for(p = start; p < NGalTree; p++) { if(centralgal < 0) terminate("centralgal < 0"); GalTree[p].FOFCentralGal = centralgal; } #endif report_memory_usage(&HighMark, "evolve_galaxies"); }
/*@brief Copies all the relevant properties from the Galaxy structure into the Galaxy output structure, some units are corrected.*/ void prepare_galaxy_for_output(int n, struct GALAXY *g, struct GALAXY_OUTPUT *o) { int j; o->Type = g->Type; o->SnapNum = g->SnapNum; o->CentralMvir = get_virial_mass(Halo[g->HaloNr].FirstHaloInFOFgroup); o->Mvir = g->Mvir; o->Rvir = g->Rvir; o->Vvir = g->Vvir; for(j = 0; j < 3; j++) { o->Pos[j] = g->Pos[j]; o->DistanceToCentralGal[j] = wrap(Halo[Halo[g->HaloNr].FirstHaloInFOFgroup].Pos[j] - g->Pos[j],BoxSize);; } o->ColdGas = g->ColdGas; o->DiskMass = g->DiskMass; o->BulgeMass = g->BulgeMass; o->HotGas = g->HotGas; o->BlackHoleMass = g->BlackHoleMass; #ifndef POST_PROCESS_MAGS #ifdef OUTPUT_REST_MAGS /* Luminosities are converted into Mags in various bands */ for(j = 0; j < NMAG; j++) o->Mag[j] = lum_to_mag(g->Lum[j][n]); #endif #endif #ifndef LIGHT_OUTPUT #ifdef GALAXYTREE o->HaloID = HaloIDs[g->HaloNr].HaloID; o->Redshift = ZZ[g->SnapNum]; int ii = (int) floor(o->Pos[0] * ScaleFactor); int jj = (int) floor(o->Pos[1] * ScaleFactor); int kk = (int) floor(o->Pos[2] * ScaleFactor); o->PeanoKey = peano_hilbert_key(ii, jj, kk, Hashbits); o->SubID = calc_big_db_subid_index(g->SnapNum, Halo[g->HaloNr].FileNr, Halo[g->HaloNr].SubhaloIndex); int tmpfirst = Halo[g->HaloNr].FirstHaloInFOFgroup; int lenmax = 0; int next = tmpfirst; while(next != -1) { if(Halo[next].Len > lenmax) { lenmax = Halo[next].Len; tmpfirst = next; } next = Halo[next].NextHaloInFOFgroup; } o->MMSubID = calc_big_db_subid_index(g->SnapNum, Halo[tmpfirst].FileNr, Halo[tmpfirst].SubhaloIndex); #endif o->LookBackTimeToSnap = NumToTime(g->SnapNum)*UnitTime_in_years/Hubble_h; o->InfallVmax = g->InfallVmax; o->InfallSnap = g->InfallSnap; o->HotRadius = g->HotRadius; #ifdef HALOPROPERTIES o->HaloM_Mean200 = g->HaloM_Mean200; o->HaloM_Crit200 = g->HaloM_Crit200; o->HaloM_TopHat = g->HaloM_TopHat; o->HaloVelDisp = g->HaloVelDisp; o->HaloVmax = g->HaloVmax; #endif o->Len = g->Len; o->Vmax = g->Vmax; o->BulgeSize = g->BulgeSize; o->EjectedMass = g->EjectedMass; o->BlackHoleGas = g->BlackHoleGas; for(j = 0; j < 3; j++) { o->Vel[j] = g->Vel[j]; #ifdef HALOSPIN o->HaloSpin[j] = g->HaloSpin[j]; #endif o->GasSpin[j] = g->GasSpin[j]; o->StellarSpin[j] = g->StellarSpin[j]; #ifdef HALOPROPERTIES o->HaloPos[j] = g->HaloPos[j]; o->HaloVel[j] = g->HaloVel[j]; o->HaloSpin[j] = g->HaloSpin[j]; #endif } o->XrayLum = g->XrayLum; o->GasDiskRadius = g->GasDiskRadius; o->StellarDiskRadius = g->StellarDiskRadius; o->CoolingRadius = g->CoolingRadius; o->ICM = g->ICM; //o->MetalsICM = CORRECTDBFLOAT(g->MetalsICM); o->MetalsICM = g->MetalsICM; o->QuasarAccretionRate = g->QuasarAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; o->RadioAccretionRate = g->RadioAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; o->CosInclination = g->CosInclination; if(g->Type == 2 || (g->Type == 1 && g->MergeOn == 1)) { o->OriMergTime=g->OriMergTime; o->MergTime = g->MergTime; } else { o->OriMergTime=0.0; o->MergTime = 0.0; } #ifndef GALAXYTREE o->HaloIndex = g->HaloNr; #endif #ifdef MBPID o->MostBoundID = g->MostBoundID; #endif #ifdef GALAXYTREE o->DisruptOn = g->DisruptOn; #endif #ifdef MERGE01 o->MergeOn = g->MergeOn; #endif //METALS /*o->MetalsColdGas = CORRECTDBFLOAT(g->MetalsColdGas); o->MetalsDiskMass = CORRECTDBFLOAT(g->MetalsDiskMass); o->MetalsBulgeMass = CORRECTDBFLOAT(g->MetalsBulgeMass); o->MetalsHotGas = CORRECTDBFLOAT(g->MetalsHotGas); o->MetalsEjectedMass = CORRECTDBFLOAT(g->MetalsEjectedMass); #ifdef METALS_SELF o->MetalsHotGasSelf = CORRECTDBFLOAT(g->MetalsHotGasSelf); #endif*/ o->MetalsColdGas = g->MetalsColdGas; o->MetalsDiskMass = g->MetalsDiskMass; o->MetalsBulgeMass = g->MetalsBulgeMass; o->MetalsHotGas = g->MetalsHotGas; o->MetalsEjectedMass = g->MetalsEjectedMass; #ifdef METALS_SELF o->MetalsHotGasSelf = g->MetalsHotGasSelf; #endif //STAR FORMATION HISTORIES / RATES #ifdef STAR_FORMATION_HISTORY o->sfh_ibin=g->sfh_ibin; for (j=0;j<=o->sfh_ibin;j++) { // Lookback time from output snap to middle of SFh bin, in years o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.-NumToTime(g->SnapNum))*UnitTime_in_years/Hubble_h; //o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.)*UnitTime_in_years/Hubble_h; //ROB: Lookback time to middle of SFH bin, in years o->sfh_dt[j]=g->sfh_dt[j]*UnitTime_in_years/Hubble_h; o->sfh_DiskMass[j]=g->sfh_DiskMass[j]; o->sfh_BulgeMass[j]=g->sfh_BulgeMass[j]; o->sfh_ICM[j]=g->sfh_ICM[j]; o->sfh_MetalsDiskMass[j]=g->sfh_MetalsDiskMass[j]; o->sfh_MetalsBulgeMass[j]=g->sfh_MetalsBulgeMass[j]; o->sfh_MetalsICM[j]=g->sfh_MetalsICM[j]; #ifdef YIELDS o->sfh_ElementsDiskMass[j]=g->sfh_ElementsDiskMass[j]; o->sfh_ElementsBulgeMass[j]=g->sfh_ElementsBulgeMass[j]; o->sfh_ElementsICM[j]=g->sfh_ElementsICM[j]; #endif } for (j=o->sfh_ibin+1;j<SFH_NBIN;j++) { o->sfh_time[j]=0.; o->sfh_DiskMass[j]=0.; o->sfh_BulgeMass[j]=0.; o->sfh_ICM[j]=0.; o->sfh_MetalsDiskMass[j]=metals_init(); o->sfh_MetalsBulgeMass[j]=metals_init(); o->sfh_MetalsICM[j]=metals_init(); #ifdef YIELDS o->sfh_ElementsDiskMass[j]=elements_init(); o->sfh_ElementsBulgeMass[j]=elements_init(); o->sfh_ElementsICM[j]=elements_init(); #endif } #endif #ifdef YIELDS /*for (j=0;j<ELEMENT_NUM;j++) { o->DiskMass_elements[j]=g->DiskMass_elements[j]; o->BulgeMass_elements[j]=g->BulgeMass_elements[j]; o->ColdGas_elements[j]=g->ColdGas_elements[j]; o->HotGas_elements[j]=g->HotGas_elements[j]; o->EjectedMass_elements[j]=g->EjectedMass_elements[j]; o->ICM_elements[j]=g->ICM_elements[j]; }*/ /*o->DiskMass_elements = CORRECTDBFLOAT(g->DiskMass_elements); o->BulgeMass_elements = CORRECTDBFLOAT(g->BulgeMass_elements); o->ColdGas_elements = CORRECTDBFLOAT(g->ColdGas_elements); o->HotGas_elements = CORRECTDBFLOAT(g->HotGas_elements); o->ICM_elements = CORRECTDBFLOAT(g->ICM_elements);*/ o->DiskMass_elements = g->DiskMass_elements; o->BulgeMass_elements = g->BulgeMass_elements; o->ColdGas_elements = g->ColdGas_elements; o->HotGas_elements = g->HotGas_elements; o->EjectedMass_elements = g->EjectedMass_elements; o->ICM_elements = g->ICM_elements; #endif //NOTE: in Msun/yr #ifdef SAVE_MEMORY o->Sfr = CORRECTDBFLOAT(g->Sfr * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); #else o->Sfr = CORRECTDBFLOAT(g->Sfr[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS); #endif //MAGNITUDES #ifdef POST_PROCESS_MAGS //Convert recorded star formation histories into mags post_process_mags(o); #else //POST_PROCESS_MAGS #ifdef OUTPUT_REST_MAGS // Luminosities are converted into Mags in various bands for(j = 0; j < NMAG; j++) { //o->Mag[j] = lum_to_mag(g->Lum[j][n]); -> DONE ON TOP FOR LIGHT_OUTPUT AS WELL o->MagBulge[j] = lum_to_mag(g->LumBulge[j][n]); o->MagDust[j] = lum_to_mag(g->LumDust[j][n]); #ifdef ICL o->MagICL[j] = lum_to_mag(g->ICLLum[j][n]); #endif } if((g->DiskMass+g->BulgeMass)> 0.0) { o->MassWeightAge = g->MassWeightAge[n] / (g->DiskMass+g->BulgeMass); o->MassWeightAge = o->MassWeightAge / 1000. * UnitTime_in_Megayears / Hubble_h; //Age in Gyr } else o->MassWeightAge = 0.; #endif //OUTPUT_REST_MAGS #ifdef OUTPUT_OBS_MAGS #ifdef COMPUTE_OBS_MAGS // Luminosities in various bands for(j = 0; j < NMAG; j++) { o->ObsMag[j] = lum_to_mag(g->ObsLum[j][n]); o->ObsMagBulge[j] = lum_to_mag(g->ObsLumBulge[j][n]); o->ObsMagDust[j] = lum_to_mag(g->ObsLumDust[j][n]); #ifdef ICL o->ObsMagICL[j] = lum_to_mag(g->ObsICL[j][n]); #endif #ifdef OUTPUT_MOMAF_INPUTS o->dObsMag[j] = lum_to_mag(g->dObsLum[j][n]); o->dObsMagBulge[j] = lum_to_mag(g->dObsLumBulge[j][n]); o->dObsMagDust[j] = lum_to_mag(g->dObsLumDust[j][n]); #endif } #endif //COMPUTE_OBS_MAGS #endif //OUTPUT_OBS_MAGS #endif //POST_PROCESS_MAGS #ifdef FIX_OUTPUT_UNITS fix_units_for_ouput(o); #endif #endif //ndef LIGHT_OUTPUT }