/**@brief join_galaxies_of_progenitors() updates the properties of the * galaxy from the dark matter halo properties and deals with * merging clocks. This routine is called by construct_galaxies * for every halo in the FOF being constructed. When there is no * galaxy in the Halo of FirstProgenitor, the first_occupied * pointer is changed to a subhalo which have the maximum mass. * * For a central galaxy it just updates its properties. For * satellites it needs to know its most massive (or only progenitor) * to keep track of the merging clock. It also finds the central * galaxies into which galaxies should merge. Type 1's * can merge if their baryonic mass is bigger than the dark matter * mass and type 2's can merge into them. Once the type 1's merge * into a type 0 all its satellites will have the merging clock * into the type 0 reset . * */ int join_galaxies_of_progenitors(int halonr, int ngalstart, int *cenngal) { int ngal, prog, i, j, first_occupied, lenmax, centralgal, mostmassive; lenmax = 0; first_occupied = Halo[halonr].FirstProgenitor; prog = Halo[halonr].FirstProgenitor; /* When there is no galaxy in the Halo of FirstProgenitor, the first_occupied * pointer is changed to a subhalo which have the maximum mass (This should * only happen in the case that the leaf on the firstprogenitor branch occurs * as a subhalo, in that case no galaxy would be assigned to it). */ if(prog >= 0) //If halo has progenitors { if(HaloAux[prog].NGalaxies == 0) //if progenitor has no galaxies while(prog >= 0) { int currentgal; for(i = 0, currentgal = HaloAux[prog].FirstGalaxy; i < HaloAux[prog].NGalaxies; i++) { if(HaloGal[currentgal].Type == 0 || HaloGal[currentgal].Type == 1) { if(Halo[prog].Len > lenmax) { lenmax = Halo[prog].Len; first_occupied = prog; //define the new first_occupied } } currentgal = HaloGal[currentgal].NextGalaxy; } prog = Halo[prog].NextProgenitor; } } lenmax = 0; prog = Halo[halonr].FirstProgenitor; mostmassive = Halo[halonr].FirstProgenitor; /* loop through all the progenitors and get the halo mass and ID * of the most massive*/ while(prog >= 0) { if(Halo[prog].Len > lenmax) { lenmax = Halo[prog].Len; mostmassive = prog; } prog = Halo[prog].NextProgenitor; } ngal = ngalstart; prog = Halo[halonr].FirstProgenitor; while(prog >= 0) { int currentgal; for(i = 0, currentgal = HaloAux[prog].FirstGalaxy; i < HaloAux[prog].NGalaxies; i++) { if(ngal >= MaxGal) { AllocValue_MaxGal *= ALLOC_INCREASE_FACTOR; MaxGal = AllocValue_MaxGal; if(MaxGal<ngal+1) MaxGal=ngal+1; Gal = myrealloc_movable(Gal, sizeof(struct GALAXY) * MaxGal); } if(*cenngal==currentgal) *cenngal=ngal; /* Copy galaxy properties from progenitor, * except for those that need initialising */ Gal[ngal] = HaloGal[currentgal]; Gal[ngal].HaloNr = halonr; Gal[ngal].CoolingRadius = 0.0; Gal[ngal].CoolingGas = 0.0; Gal[ngal].PrimordialAccretionRate = 0.0; Gal[ngal].CoolingRate = 0.0; Gal[ngal].CoolingRate_beforeAGN = 0.0; Gal[ngal].Sfr = 0.0; Gal[ngal].SfrBulge = 0.0; Gal[ngal].QuasarAccretionRate=0.0; Gal[ngal].RadioAccretionRate=0.0; #ifdef GALAXYTREE Gal[ngal].FirstProgGal = HaloGal[currentgal].GalTreeIndex; /* CHECK */ #endif // To fail this check means that we copy in a failed galaxy mass_checks("Middle of join_galaxies_of_progenitors",ngal); /* Update Properties of this galaxy with physical properties of halo */ /* this deals with the central galaxies of subhalos */ if(Gal[ngal].Type == 0 || Gal[ngal].Type == 1) { if(prog == first_occupied) { #ifdef HALOPROPERTIES Gal[ngal].HaloM_Mean200 = Halo[halonr].M_Mean200; Gal[ngal].HaloM_Crit200 = Halo[halonr].M_Crit200; Gal[ngal].HaloM_TopHat = Halo[halonr].M_TopHat; Gal[ngal].HaloVelDisp = Halo[halonr].VelDisp; Gal[ngal].HaloVmax = Halo[halonr].Vmax; #endif 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]; #ifdef HALOPROPERTIES Gal[ngal].HaloPos[j] = Halo[halonr].Pos[j]; Gal[ngal].HaloVel[j] = Halo[halonr].Vel[j]; #endif } Gal[ngal].Len = Halo[halonr].Len; // FOFCentralGal property in case that is different from FirstGalaxy if(halonr == Halo[halonr].FirstHaloInFOFgroup) update_centralgal(ngal, halonr); else update_type_1(ngal, halonr, prog); if(DiskRadiusModel == 1 || DiskRadiusModel == 2) { Gal[ngal].GasDiskRadius = get_disk_radius(halonr, ngal); Gal[ngal].StellarDiskRadius = Gal[ngal].GasDiskRadius; } Gal[ngal].Vmax = Halo[halonr].Vmax; } else //type 2 galaxies { update_type_2(ngal, halonr, prog, mostmassive); } } /* Note: Galaxies that are already type=2 do not need a special treatment at this point */ if(Gal[ngal].Type < 0 || Gal[ngal].Type > 2) terminate("Unknown galaxy type\n"); ngal++; currentgal = HaloGal[currentgal].NextGalaxy; } prog = Halo[prog].NextProgenitor; } /* If there are no progenitors with galaxies, a new galaxy is created. * However, if it's a subhalo, no galaxy is placed, since it would stay * at zero luminosity. */ if(ngal == 0) { *cenngal=0; if(Halo[halonr].FirstHaloInFOFgroup == halonr) { init_galaxy(ngal, halonr); ngal++; } } /* satelites (type 2's) will preferably merge onto this type 1 rather than the type 0 */ for(i = ngalstart, centralgal = -1; i < ngal; i++) if(Gal[i].Type == 0 || Gal[i].Type == 1) { if(centralgal != -1) terminate("Subhalo hosts more than one Type 0/1\n"); centralgal = i; } for(i = ngalstart; i < ngal; i++) { Gal[i].CentralGal = centralgal; if(centralgal != -1) for(j = 0; j < 3; j++) Gal[i].MergCentralPos[j] = Gal[centralgal].Pos[j]; } /* Satellites whose type 1 has merged into type 0, will be reset to merge * into the type 0. */ if(centralgal == -1 && ngal != ngalstart) { for(i = ngalstart; i < ngal; i++) { Gal[i].CentralGal = *cenngal; for(j = 0; j < 3; j++) Gal[i].MergCentralPos[j] = Gal[*cenngal].Pos[j]; } } for (i = ngalstart; i<ngal; i++) mass_checks("Bottom of join_galaxies_of_progenitors",i); report_memory_usage(&HighMark, "join_galaxies"); return ngal; }
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; }