double get_merging_radius(int halonr, int mother_halonr, int p) { int central_halonr; double SatelliteRadius, MotherHaloRvir; /* recipe updated for more accurate merging time (see BT eq 7.26), now satellite radius at previous timestep is included */ central_halonr = Halo[Halo[halonr].Descendant].FirstProgenitor; if(Gal[p].Type == 1) central_halonr=mother_halonr; if(central_halonr == halonr) terminate("central_halonr == halonr"); /* in physical length (/(1 + ZZ[Halo[halonr].SnapNum]))*/ SatelliteRadius = separation_halo(central_halonr,halonr)/(1 + ZZ[Halo[halonr].SnapNum]); MotherHaloRvir = get_virial_radius(mother_halonr); if(SatelliteRadius > MotherHaloRvir) SatelliteRadius = MotherHaloRvir; return SatelliteRadius; }
double estimate_merging_time(int halonr, int mother_halonr, int p) { int central_halonr; double coulomb, mergtime, SatelliteMass, SatelliteRadius, MotherHaloRvir; /** @brief Binney & Tremaine 1987 - 7.26 merging time for satellites due to * dynamical friction. After Delucia2007 *2, shown to agree with * Kolchin2008 simulations in Delucia2010. This is set when a galaxy * becomes a type 2 or being a type 1 \f$M_{\rm{star}}>M_{\rm{vir}}\f$. * In DeLucia2007 they could only merge into a type 0, now (after * guo2010) they can merge into a type 1. */ /* recipe updated for more accurate merging time (see BT eq 7.26), now satellite radius at previous timestep is included */ central_halonr = Halo[Halo[halonr].Descendant].FirstProgenitor; if(Gal[p].Type == 1) central_halonr=mother_halonr; if(central_halonr == halonr) { terminate("can't be...!\n"); } coulomb = log(Halo[mother_halonr].Len / ((double) Halo[halonr].Len) + 1); /* should include stellar+cold gas in SatelliteMass! */ SatelliteMass = get_virial_mass(halonr)+(Gal[p].DiskMass+Gal[p].BulgeMass); SatelliteRadius = separation_halo(central_halonr,halonr)/(1 + ZZ[Halo[halonr].SnapNum]); int j; for (j = 0; j < 3; j++) Gal[p].DistanceToCentralGal[j] = wrap(Halo[central_halonr].Pos[j] - Halo[halonr].Pos[j], BoxSize); MotherHaloRvir = get_virial_radius(mother_halonr); if(SatelliteRadius > MotherHaloRvir) SatelliteRadius = MotherHaloRvir; if(SatelliteMass > 0.0) { mergtime = 1.17 * SatelliteRadius * SatelliteRadius * get_virial_velocity(mother_halonr) / (coulomb * G * SatelliteMass); // Binney & Tremaine Eq.7.26 /* change introduced by Delucia2007 to fit observations */ mergtime = 2.*mergtime; } else mergtime = -99999.9; return mergtime; }
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); }
void prepare_galaxy_for_output(int filenr, int tree, struct GALAXY *g, struct GALAXY_OUTPUT *o) { int j, step; o->SnapNum = g->SnapNum; o->Type = g->Type; // assume that because there are so many files, the trees per file will be less than 100000 // required for limits of long long if(LastFile>=10000) { assert( g->GalaxyNr < TREE_MUL_FAC ); // breaking tree size assumption assert(tree < (FILENR_MUL_FAC/10)/TREE_MUL_FAC); o->GalaxyIndex = g->GalaxyNr + TREE_MUL_FAC * tree + (FILENR_MUL_FAC/10) * filenr; assert( (o->GalaxyIndex - g->GalaxyNr - TREE_MUL_FAC*tree)/(FILENR_MUL_FAC/10) == filenr ); assert( (o->GalaxyIndex - g->GalaxyNr -(FILENR_MUL_FAC/10)*filenr) / TREE_MUL_FAC == tree ); assert( o->GalaxyIndex - TREE_MUL_FAC*tree - (FILENR_MUL_FAC/10)*filenr == g->GalaxyNr ); o->CentralGalaxyIndex = HaloGal[HaloAux[Halo[g->HaloNr].FirstHaloInFOFgroup].FirstGalaxy].GalaxyNr + TREE_MUL_FAC * tree + (FILENR_MUL_FAC/10) * filenr; } else { assert( g->GalaxyNr < TREE_MUL_FAC ); // breaking tree size assumption assert(tree < FILENR_MUL_FAC/TREE_MUL_FAC); o->GalaxyIndex = g->GalaxyNr + TREE_MUL_FAC * tree + FILENR_MUL_FAC * filenr; assert( (o->GalaxyIndex - g->GalaxyNr - TREE_MUL_FAC*tree)/FILENR_MUL_FAC == filenr ); assert( (o->GalaxyIndex - g->GalaxyNr -FILENR_MUL_FAC*filenr) / TREE_MUL_FAC == tree ); assert( o->GalaxyIndex - TREE_MUL_FAC*tree - FILENR_MUL_FAC*filenr == g->GalaxyNr ); o->CentralGalaxyIndex = HaloGal[HaloAux[Halo[g->HaloNr].FirstHaloInFOFgroup].FirstGalaxy].GalaxyNr + TREE_MUL_FAC * tree + FILENR_MUL_FAC * filenr; } o->SAGEHaloIndex = g->HaloNr; o->SAGETreeIndex = tree; o->SimulationHaloIndex = Halo[g->HaloNr].MostBoundID; o->mergeType = g->mergeType; o->mergeIntoID = g->mergeIntoID; o->mergeIntoSnapNum = g->mergeIntoSnapNum; o->dT = g->dT * UnitTime_in_s / SEC_PER_MEGAYEAR; for(j = 0; j < 3; j++) { o->Pos[j] = g->Pos[j]; o->Vel[j] = g->Vel[j]; o->Spin[j] = Halo[g->HaloNr].Spin[j]; } o->Len = g->Len; o->Mvir = g->Mvir; o->CentralMvir = get_virial_mass(Halo[g->HaloNr].FirstHaloInFOFgroup); o->Rvir = get_virial_radius(g->HaloNr); // output the actual Rvir, not the maximum Rvir o->Vvir = get_virial_velocity(g->HaloNr); // output the actual Vvir, not the maximum Vvir o->Vmax = g->Vmax; o->VelDisp = Halo[g->HaloNr].VelDisp; o->ColdGas = g->ColdGas; o->StellarMass = g->StellarMass; o->BulgeMass = g->BulgeMass; o->HotGas = g->HotGas; o->EjectedMass = g->EjectedMass; o->BlackHoleMass = g->BlackHoleMass; o->ICS = g->ICS; o->MetalsColdGas = g->MetalsColdGas; o->MetalsStellarMass = g->MetalsStellarMass; o->MetalsBulgeMass = g->MetalsBulgeMass; o->MetalsHotGas = g->MetalsHotGas; o->MetalsEjectedMass = g->MetalsEjectedMass; o->MetalsICS = g->MetalsICS; o->SfrDisk = 0.0; o->SfrBulge = 0.0; o->SfrDiskZ = 0.0; o->SfrBulgeZ = 0.0; // NOTE: in Msun/yr for(step = 0; step < STEPS; step++) { o->SfrDisk += g->SfrDisk[step] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS / STEPS; o->SfrBulge += g->SfrBulge[step] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS / STEPS; if(g->SfrDiskColdGas[step] > 0.0) o->SfrDiskZ += g->SfrDiskColdGasMetals[step] / g->SfrDiskColdGas[step] / STEPS; if(g->SfrBulgeColdGas[step] > 0.0) o->SfrBulgeZ += g->SfrBulgeColdGasMetals[step] / g->SfrBulgeColdGas[step] / STEPS; } o->DiskScaleRadius = g->DiskScaleRadius; if (g->Cooling > 0.0) o->Cooling = log10(g->Cooling * UnitEnergy_in_cgs / UnitTime_in_s); else o->Cooling = 0.0; if (g->Heating > 0.0) o->Heating = log10(g->Heating * UnitEnergy_in_cgs / UnitTime_in_s); else o->Heating = 0.0; o->QuasarModeBHaccretionMass = g->QuasarModeBHaccretionMass; o->TimeOfLastMajorMerger = g->TimeOfLastMajorMerger * UnitTime_in_Megayears; o->TimeOfLastMinorMerger = g->TimeOfLastMinorMerger * UnitTime_in_Megayears; o->OutflowRate = g->OutflowRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS; //infall properties if(g->Type != 0) { o->infallMvir = g->infallMvir; o->infallVvir = g->infallVvir; o->infallVmax = g->infallVmax; } else { o->infallMvir = 0.0; o->infallVvir = 0.0; o->infallVmax = 0.0; } }
int join_galaxies_of_progenitors(int halonr, int ngalstart) { int ngal, prog, mother_halo=-1, i, j, first_occupied, lenmax, lenoccmax, centralgal; double previousMvir, previousVvir, previousVmax; int step; lenmax = 0; lenoccmax = 0; first_occupied = Halo[halonr].FirstProgenitor; prog = Halo[halonr].FirstProgenitor; if(prog >=0) if(HaloAux[prog].NGalaxies > 0) lenoccmax = -1; // Find most massive progenitor that contains an actual galaxy // Maybe FirstProgenitor never was FirstHaloInFOFGroup and thus has no galaxy while(prog >= 0) { if(Halo[prog].Len > lenmax) { lenmax = Halo[prog].Len; mother_halo = prog; } if(lenoccmax != -1 && Halo[prog].Len > lenoccmax && HaloAux[prog].NGalaxies > 0) { lenoccmax = Halo[prog].Len; first_occupied = prog; } prog = Halo[prog].NextProgenitor; } ngal = ngalstart; prog = Halo[halonr].FirstProgenitor; while(prog >= 0) { for(i = 0; i < HaloAux[prog].NGalaxies; i++) { assert(ngal < FoF_MaxGals); // This is the cruical line in which the properties of the progenitor galaxies // are copied over (as a whole) to the (temporary) galaxies Gal[xxx] in the current snapshot // After updating their properties and evolving them // they are copied to the end of the list of permanent galaxies HaloGal[xxx] Gal[ngal] = HaloGal[HaloAux[prog].FirstGalaxy + i]; Gal[ngal].HaloNr = halonr; Gal[ngal].dT = -1.0; // this deals with the central galaxies of (sub)halos if(Gal[ngal].Type == 0 || Gal[ngal].Type == 1) { // this halo shouldn't hold a galaxy that has already merged; remove it from future processing if(Gal[ngal].mergeType != 0) { Gal[ngal].Type = 3; continue; } // remember properties from the last snapshot previousMvir = Gal[ngal].Mvir; previousVvir = Gal[ngal].Vvir; previousVmax = Gal[ngal].Vmax; if(prog == first_occupied) { // update properties of this galaxy with physical properties of halo Gal[ngal].MostBoundID = Halo[halonr].MostBoundID; for(j = 0; j < 3; j++) { Gal[ngal].Pos[j] = Halo[halonr].Pos[j]; Gal[ngal].Vel[j] = Halo[halonr].Vel[j]; } Gal[ngal].Len = Halo[halonr].Len; Gal[ngal].Vmax = Halo[halonr].Vmax; Gal[ngal].deltaMvir = get_virial_mass(halonr) - Gal[ngal].Mvir; if(get_virial_mass(halonr) > Gal[ngal].Mvir) { Gal[ngal].Rvir = get_virial_radius(halonr); // use the maximum Rvir in model Gal[ngal].Vvir = get_virial_velocity(halonr); // use the maximum Vvir in model } Gal[ngal].Mvir = get_virial_mass(halonr); Gal[ngal].Cooling = 0.0; Gal[ngal].Heating = 0.0; Gal[ngal].QuasarModeBHaccretionMass = 0.0; Gal[ngal].OutflowRate = 0.0; Gal[ngal].Lx_bol = 0.0; for(step = 0; step < STEPS; step++) { Gal[ngal].SfrDisk[step] = Gal[ngal].SfrBulge[step] = 0.0; Gal[ngal].SfrDiskColdGas[step] = Gal[ngal].SfrDiskColdGasMetals[step] = 0.0; Gal[ngal].SfrBulgeColdGas[step] = Gal[ngal].SfrBulgeColdGasMetals[step] = 0.0; } if(halonr == Halo[halonr].FirstHaloInFOFgroup) { // a central galaxy Gal[ngal].mergeType = 0; Gal[ngal].mergeIntoID = -1; Gal[ngal].MergTime = 999.9; Gal[ngal].DiskScaleRadius = get_disk_radius(halonr, ngal); Gal[ngal].Type = 0; } else { // a satellite with subhalo Gal[ngal].mergeType = 0; Gal[ngal].mergeIntoID = -1; if(Gal[ngal].Type == 0) // remember the infall properties before becoming a subhalo { Gal[ngal].infallMvir = previousMvir; Gal[ngal].infallVvir = previousVvir; Gal[ngal].infallVmax = previousVmax; } if(Gal[ngal].Type == 0 || Gal[ngal].MergTime > 999.0) // here the galaxy has gone from type 1 to type 2 or otherwise doesn't have a merging time. Gal[ngal].MergTime = estimate_merging_time(halonr, Halo[halonr].FirstHaloInFOFgroup, ngal); Gal[ngal].Type = 1; } } else { // an orhpan satellite galaxy - these will merge or disrupt within the current timestep Gal[ngal].deltaMvir = -1.0*Gal[ngal].Mvir; Gal[ngal].Mvir = 0.0; if(Gal[ngal].MergTime > 999.0 || Gal[ngal].Type == 0) { // here the galaxy has gone from type 0 to type 2 - merge it! Gal[ngal].MergTime = 0.0; Gal[ngal].infallMvir = previousMvir; Gal[ngal].infallVvir = previousVvir; Gal[ngal].infallVmax = previousVmax; } Gal[ngal].Type = 2; } } ngal++; } prog = Halo[prog].NextProgenitor; } if(ngal == 0) { // We have no progenitors with galaxies. This means we create a new galaxy. init_galaxy(ngal, halonr); ngal++; } // Per Halo there can be only one Type 0 or 1 galaxy, all others are Type 2 (orphan) // In fact, this galaxy is very likely to be the first galaxy in the halo if // first_occupied==FirstProgenitor and the Type0/1 galaxy in FirstProgenitor was also the first one // This cannot be guaranteed though for the pathological first_occupied!=FirstProgenitor case for(i = ngalstart, centralgal = -1; i < ngal; i++) { if(Gal[i].Type == 0 || Gal[i].Type == 1) { assert(centralgal == -1); centralgal = i; } } for(i = ngalstart; i < ngal; i++) Gal[i].CentralGal = centralgal; return ngal; }