void reincorporate_gas(int p, double dt)
{
  double reincorporated, fraction, reinc_time;

  reincorporated = 0.;

  mass_checks("reincorporate_gas #1",p);

  /* DeLucia2007 -> Mdot_eject=-gama_ej * M_ejected/tdyn */
  if(ReIncorporationRecipe == 0)
 	reincorporated = ReIncorporationFactor * Gal[p].EjectedMass / (Gal[p].Rvir / Gal[p].Vvir) * dt;

  /* Guo2010 -> Mdot_eject=-gama_ej * M_ejected/tdyn * Vvir/220 */
  else
 	if(ReIncorporationRecipe == 1)
      reincorporated = ReIncorporationFactor * Gal[p].EjectedMass / (Gal[p].Rvir / Gal[p].Vvir) * Gal[p].Vvir/220. *dt ;

   /* Henriques2012b Mdot_eject=-gama_ej*M_ejected*M_vir
    * Mvir should be in units of 1e12, but inside the
    * code Mvir is already in units of 1.e10*/
 	else
 	  if(ReIncorporationRecipe == 2)
 	  {
 	  	// Oppenheimer & Dave 2008
 	  	/* reinc_time= pow(Gal[p].Mvir/Hubble_h,-0.6)*ReIncorporationFactor/UnitTime_in_years;
 	  	   if(Gal[p].Mvir/Hubble_h > 500.)
 	  	   reinc_time= pow(500.,-0.6)*ReIncorporationFactor/UnitTime_in_years;
 	  	   reincorporated = Gal[p].EjectedMass / reinc_time * dt; */

 	  	reinc_time= (Hubble_h/Gal[p].Mvir)*(ReIncorporationFactor/UnitTime_in_years);
 	  	reincorporated = Gal[p].EjectedMass / reinc_time * dt;

// 	  	reinc_time= (Hubble_h)*(ReIncorporationFactor/UnitTime_in_years);
// 	  	reincorporated = Gal[p].EjectedMass / reinc_time * dt;

 	    /*reinc_time= ReIncorporationFactor/UnitTime_in_years * pow((1+ZZ[Gal[p].SnapNum]),ReincZpower)
 	                * pow(Gal[p].Vvir/220.,-ReincVelocitypower) / (hubble_of_z(Gal[p].HaloNr));
 	            reincorporated = Gal[p].EjectedMass / reinc_time  *dt ;*/



 	  }

  if(FeedbackRecipe == 1)
  {
	  reincorporated = ReIncorporationFactor * Gal[p].EjectedMass /
	  	(Gal[p].Rvir * min(FeedbackEjectionEfficiency,1.)*sqrt(EtaSNcode * EnergySNcode)/(Gal[p].Vvir*Gal[p].Vvir))
	  	* Gal[p].Vvir/220. * 1.e-6* dt ;

	  //reincorporated = ReIncorporationFactor * Gal[p].EjectedMass / (Gal[p].Rvir / Gal[p].Vvir) *
	  	//                   min(FeedbackEjectionEfficiency,1.) * Gal[p].Vvir/220. *dt ;
	  //reincorporated = ReIncorporationFactor * Gal[p].EjectedMass / (Gal[p].Rvir / Gal[p].Vvir) * Gal[p].Vvir/220. *dt ;
	  //reincorporated = 0.;
  }

  if (reincorporated > Gal[p].EjectedMass)
    reincorporated = Gal[p].EjectedMass;
	
  mass_checks("reincorporate_gas #1.5",p);

  /*Update ejected and hot gas contents*/
  if (Gal[p].EjectedMass > 0.) {
    fraction=((float)reincorporated)/Gal[p].EjectedMass;
    //printf("%s","Gas Reincorporated: ");
    //printf("%lf \n",reincorporated);
    transfer_gas(p,"Hot",p,"Ejected",fraction,"reincorporate_gas", __LINE__);
  }

  mass_checks("reincorporate_gas #2",p);

}
void add_galaxies_together(int t, int p)
{
  /** @brief All the components of the satellite galaxy are added to the
   *         correspondent component of the central galaxy. Cold gas spin
   *         is updated and a bulge is formed at the central galaxy, with
   *         the stars of the satellite if  BulgeFormationInMinorMergersOn=1.
   *
   * TODO Even though galaxy p has been set to type 3 (ie a non-galaxy), it would
   * make mass conservation more explicit to zero the properties of galaxy p after
   * the merger.
   * TODO Correct artificial diffusion of metals when BulgeFormationInMinorMergersOn=1. */
  int outputbin, j;
  float tspin[3],tmass,pmass;

  /* t central, p satellite */

  mass_checks("add_galaxies_together #0",p);
  mass_checks("add_galaxies_together #0.1",t);

  /* angular momentum transfer between gas*/
  tmass= Gal[t].ColdGas;
  pmass= Gal[p].ColdGas;
  
  Gal[t].MergeSat +=(Gal[p].DiskMass+Gal[p].BulgeMass);
  Gal[p].MergeSat=0.;

  transfer_gas(t,"Cold",p,"Cold",1.);
  transfer_gas(t,"Hot",p,"Hot",1.);
  transfer_gas(t,"Ejected",p,"Ejected",1.); //TODO chose move to ejected or hot
  if(BulgeFormationInMinorMergersOn) 
    transfer_stars(t,"Bulge",p,"Disk",1.);
  else
    transfer_stars(t,"Disk",p,"Disk",1.);
  transfer_stars(t,"Bulge",p,"Bulge",1.);
  transfer_stars(t,"ICM",p,"ICM",1.);

  Gal[t].BlackHoleMass += Gal[p].BlackHoleMass;    
  Gal[p].BlackHoleMass=0.;
  Gal[t].BlackHoleGas += Gal[p].BlackHoleGas;    
  Gal[p].BlackHoleGas=0.;
  Gal[t].StarMerge += Gal[p].StarMerge;
  Gal[p].StarMerge=0.;

  mass_checks("add_galaxies_together #1",p);
  mass_checks("add_galaxies_together #1.1",t);

  /*update the gas spin*/
  for(j=0;j<3;j++)
    tspin[j]=Gal[t].GasSpin[j]*tmass+Gal[t].HaloSpin[j]*pmass;
  if (Gal[t].ColdGas != 0)
    for (j=0;j<3;j++)
     Gal[t].GasSpin[j]=tspin[j]/(Gal[t].ColdGas); 

#ifdef SAVE_MEMORY
  Gal[t].Sfr += Gal[p].Sfr;
#else
  for(outputbin = 0; outputbin < NOUT; outputbin++)
    Gal[t].Sfr[outputbin] += Gal[p].Sfr[outputbin];
#endif

  if(BulgeFormationInMinorMergersOn) {
#ifdef SAVE_MEMORY
    Gal[t].SfrBulge += Gal[p].Sfr;
#else
    for(outputbin = 0; outputbin < NOUT; outputbin++)
      Gal[t].SfrBulge[outputbin] += Gal[p].Sfr[outputbin];
#endif
  }

  /* Add the black hole accretion rates.  This makes little sense but is not
   * used if the superior BlackHoleGrowth==1 switch is on. */
  Gal[t].QuasarAccretionRate += Gal[p].QuasarAccretionRate;
  Gal[t].RadioAccretionRate += Gal[p].RadioAccretionRate;

#ifndef  POST_PROCESS_MAGS
/* Add the luminosities of the satellite and central galaxy */
#ifdef OUTPUT_REST_MAGS
  for(outputbin = 0; outputbin < NOUT; outputbin++)
    {

    for(j = 0; j < NMAG; j++) {
      Gal[t].Lum[j][outputbin] += Gal[p].Lum[j][outputbin];
      Gal[t].YLum[j][outputbin] += Gal[p].YLum[j][outputbin];
#ifdef ICL
      Gal[t].ICLLum[j][outputbin] += Gal[p].ICLLum[j][outputbin];
#endif
    }
    if(BulgeFormationInMinorMergersOn) {
      for(j = 0; j < NMAG; j++) {
	Gal[t].LumBulge[j][outputbin] += Gal[p].Lum[j][outputbin];
	Gal[t].YLumBulge[j][outputbin] += Gal[p].YLum[j][outputbin];
      }
    }
    else {
      for(j = 0; j < NMAG; j++) {
	Gal[t].LumBulge[j][outputbin]  += Gal[p].LumBulge[j][outputbin];
	Gal[t].YLumBulge[j][outputbin] += Gal[p].YLumBulge[j][outputbin];
      }
    }
    
    Gal[t].MassWeightAge[outputbin] += Gal[p].MassWeightAge[outputbin];
  }
#endif // OUTPUT_REST_MAGS 

#ifdef COMPUTE_OBS_MAGS 
  for(outputbin = 0; outputbin < NOUT; outputbin++)
    {
      for(j = 0; j < NMAG; j++) {
      Gal[t].ObsLum[j][outputbin]   += Gal[p].ObsLum[j][outputbin];
      Gal[t].ObsYLum[j][outputbin]  += Gal[p].ObsYLum[j][outputbin];
#ifdef ICL
      Gal[t].ObsICL[j][outputbin]  += Gal[p].ObsICL[j][outputbin];
#endif

#ifdef OUTPUT_MOMAF_INPUTS
      Gal[t].dObsLum[j][outputbin] += Gal[p].dObsLum[j][outputbin];
      Gal[t].dObsYLum[j][outputbin] += Gal[p].dObsYLum[j][outputbin];
#endif
    }
    if(BulgeFormationInMinorMergersOn) {
      for(j = 0; j < NMAG; j++) {
	Gal[t].ObsLumBulge[j][outputbin]   += Gal[p].ObsLum[j][outputbin];
	Gal[t].ObsYLumBulge[j][outputbin]  += Gal[p].ObsYLum[j][outputbin];
#ifdef OUTPUT_MOMAF_INPUTS
	Gal[t].dObsLumBulge[j][outputbin]  += Gal[p].dObsLum[j][outputbin];
	Gal[t].dObsYLumBulge[j][outputbin] += Gal[p].dObsYLum[j][outputbin];
#endif
      }
    }
    else 
    {
      for(j = 0; j < NMAG; j++) {
	Gal[t].ObsLumBulge[j][outputbin]   += Gal[p].ObsLumBulge[j][outputbin];
	Gal[t].ObsYLumBulge[j][outputbin]  += Gal[p].ObsYLumBulge[j][outputbin];
#ifdef OUTPUT_MOMAF_INPUTS
	Gal[t].dObsLumBulge[j][outputbin]  += Gal[p].dObsLumBulge[j][outputbin];
	Gal[t].dObsYLumBulge[j][outputbin] += Gal[p].dObsYLumBulge[j][outputbin];
#endif
      }
    }
  }
#endif //COMPUTE_OBS_MAGS 
#endif  //POST_PROCESS_MAGS
}
double collisional_starburst_recipe(double mass_ratio, int merger_centralgal, int centralgal,
				  double time, double deltaT, int nstep) //ROB: New variable 'nstep' added, for use in update_yields()
{
  /** @brief If StarBurstRecipe = 1 (since Croton2006), the Somerville 2001
   *         model of bursts is used. The burst can happen for both major
   *         and minor mergers, with a fraction of the added cold gas from
   *         the satellite and central being consumed. SN Feedback from
   *         starformation is computed and the sizes of bulge and disk
   *         followed (not done for the other burst mode).*/

  double mstars, reheated_mass, ejected_mass, fac, metallicitySF;
  double CentralVvir, eburst, MergeCentralVvir, Ggas, EjectVmax, EjectVvir;
  double SN_Energy, Reheat_Energy;

  /* This is the major and minor merger starburst recipe of Somerville 2001.
   * The coefficients in eburst are taken from TJ Cox's PhD thesis and should
   * be more accurate then previous. */

  Ggas=Gal[merger_centralgal].ColdGas;

  /* the bursting fraction given the mass ratio */
  /* m_dot = 0.56*(m_sat/m_central)^0.7*m_gas */
  eburst = SfrBurstEfficiency * pow(mass_ratio, SfrBurstSlope);
  //eburst = 0.56 * pow(mass_ratio, 0.7);
  mstars = eburst * Gal[merger_centralgal].ColdGas;
  if(mstars < 0.0)
    mstars = 0.0;

  /*  this bursting results in SN feedback on the cold/hot gas
   *  TODO this is the same code used in star_formation_and_feedback.c
   *       and should be merged if possible. */

  if(FeedbackRecipe == 0 || FeedbackRecipe == 1) {
    if (Gal[merger_centralgal].Type == 0)
      reheated_mass = FeedbackReheatingEpsilon * 
	mstars*(.5+1./pow(Gal[merger_centralgal].Vmax/ReheatPreVelocity,ReheatSlope));
    else
      reheated_mass = FeedbackReheatingEpsilon * 
	mstars*(.5+1./pow(Gal[merger_centralgal].InfallVmax/ReheatPreVelocity,ReheatSlope));
  }


  //Make sure that the energy used does not exceed the SN energy (central subhalo Vvir used)
  if(FeedbackRecipe == 0 || FeedbackRecipe == 1) {
    if (reheated_mass * Gal[merger_centralgal].Vvir * Gal[merger_centralgal].Vvir > mstars * EtaSNcode * EnergySNcode)
      reheated_mass = mstars * EtaSNcode * EnergySNcode / Gal[merger_centralgal].Vvir / Gal[merger_centralgal].Vvir;
  }

  /*  cant use more cold gas than is available! so balance SF and feedback */
  if((mstars + reheated_mass) > Gal[merger_centralgal].ColdGas) {
    fac = Gal[merger_centralgal].ColdGas / (mstars + reheated_mass);
    mstars *= fac;
    reheated_mass *= fac;
  }

  if (merger_centralgal == centralgal)
    {
  	  EjectVmax=Gal[centralgal].Vmax;
  	  EjectVvir=Gal[centralgal].Vvir;// main halo Vvir
    }
  else
    {
  	  EjectVmax=Gal[merger_centralgal].InfallVmax;
  	  EjectVvir=Gal[merger_centralgal].Vvir; //central subhalo Vvir
    }

  /*  determine ejection*/
  if(FeedbackRecipe == 0) {
      ejected_mass = (FeedbackEjectionEfficiency* (EtaSNcode * EnergySNcode) *mstars
	                  * min(1./FeedbackEjectionEfficiency,.5+1/pow(EjectVmax/EjectPreVelocity,EjectSlope))
                      - reheated_mass*EjectVvir*EjectVvir) /(EjectVvir*EjectVvir);
    }
  else if(FeedbackRecipe == 1)
  {  
  	SN_Energy = .5 * mstars * (EtaSNcode * EnergySNcode);
  	Reheat_Energy = .5 * reheated_mass * EjectVvir * EjectVvir;
 
  	ejected_mass = (SN_Energy - Reheat_Energy)/(0.5 * FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode));

  	if(FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode)<EjectVvir*EjectVvir)
  		ejected_mass =0.0;
    }
  
  // Finished calculating mass exchanges, so just check that none are negative
  if (reheated_mass < 0.0) reheated_mass = 0.0;
  if (ejected_mass < 0.0) ejected_mass = 0.0;	 	  
   
  /*  update the star formation rate */
#ifdef SAVE_MEMORY
  Gal[merger_centralgal].Sfr += mstars / deltaT;
#else
  for(outputbin = 0; outputbin < NOUT; outputbin++) {
    if(Halo[halonr].SnapNum == ListOutputSnaps[outputbin]) {
      Gal[merger_centralgal].Sfr[outputbin] += mstars / deltaT;
      break;
    }
  }
#endif

  /* Store the value of the metallicity of the cold phase when SF occurs.
   * Used to update luminosities below */
#ifdef METALS
  //metallicitySF = Gal[merger_centralgal].MetalsColdGas.type2/Gal[merger_centralgal].ColdGas;
  metallicitySF = metals_total(Gal[merger_centralgal].MetalsColdGas)/Gal[merger_centralgal].ColdGas;
#else
  metallicitySF = Gal[merger_centralgal].MetalsColdGas/Gal[merger_centralgal].ColdGas;
#endif

  mass_checks("collisional_starburst_recipe #1",merger_centralgal);

  if (mstars > 0.) 
    update_from_star_formation(merger_centralgal, mstars, deltaT/STEPS, nstep);

  mass_checks("collisional_starburst_recipe #2",merger_centralgal);
      
  // Do not call if Gal[merger_centralgal].ColdGas < 1e-8?
  if (reheated_mass + ejected_mass > 0.)
    update_from_feedback(merger_centralgal, centralgal, reheated_mass, ejected_mass);
 
#ifndef POST_PROCESS_MAGS
  /*  update the luminosities due to the stars formed */
  if (mstars > 0.0) 
    add_to_luminosities(merger_centralgal, mstars, time, metallicitySF);
#endif
 
  if (Ggas > 0.)
    return mstars/Ggas;
  else
    return 0.0;

}
/* 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 deal_with_galaxy_merger(int p, int merger_centralgal, int centralgal, double time, double deltaT, int nstep)
{

/** @brief Deals with the physics triggered by mergers, according to the mass
 *         fraction of the merger \f$(M_{\rm{sat}}/M_{\rm{central}}><0.3)\f$.
 *         Add the cold and stellar phase of the satellite galaxy to the central
 *         one, form a bulge at the central galaxy with the stars from the
 *         satellite in a minor merger if BulgeFormationInMinorMergersOn=1.
 *         Grows black hole through accretion from cold gas "quasar mode". 
 *         If StarBurstRecipe = 0, the Somerville 2001 model
 *         of bursts is used, SN Feedback from starformation is computed and
 *         the sizes of bulge and disk followed. When a major merger occurs,
 *         the disk of both merging galaxies is completely destroyed to form
 *         a bulge. */

  double mi, ma, mass_ratio, Mcstar, Mcgas, Mcbulge, Mpstar, Mpgas,Mpbulge;
  double frac;
#ifdef GALAXYTREE
  int q;

  mass_checks("deal_with_galaxy_merger #0",p);
  mass_checks("deal_with_galaxy_merger #0",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #0",centralgal);

  q = Gal[merger_centralgal].FirstProgGal;
  if(q >= 0)
    {
      while(GalTree[q].NextProgGal >= 0)
        q = GalTree[q].NextProgGal;
        
      GalTree[q].NextProgGal = Gal[p].FirstProgGal;
      
      if(GalTree[q].NextProgGal >= NGalTree)
	{
	  printf("q=%d p=%d GalTree[q].NextProgGal=%d NGalTree=%d\n",
		 q, p, GalTree[q].NextProgGal, NGalTree);
	  terminate("problem");
	}
    }

  if(q < 0)
    terminate("may not happen");

  q = GalTree[q].NextProgGal;

  if(HaloGal[GalTree[q].HaloGalIndex].GalTreeIndex != q)
    terminate("inconsistency");

  HaloGal[GalTree[q].HaloGalIndex].MergeOn = 2;

  if(Gal[p].Type == 1)
    HaloGal[GalTree[q].HaloGalIndex].MergeOn = 3;
#endif


  /* flag galaxy as finished */
  Gal[p].Type = 3;

  /*  calculate mass ratio of merging galaxies */
  mi = Gal[p].DiskMass+Gal[p].BulgeMass+Gal[p].ColdGas;
  ma = Gal[merger_centralgal].DiskMass+Gal[merger_centralgal].BulgeMass+Gal[merger_centralgal].ColdGas;
  if(max(mi,ma) > 0.)
    mass_ratio = min(mi,ma) / max(mi,ma);
  else
    mass_ratio = 1.0;

  /* record the gas and stellar component  mass of merger central and satellite
   * galaxies before the before merger */
  Mcstar=(Gal[merger_centralgal].DiskMass+Gal[merger_centralgal].BulgeMass);
  Mcbulge=Gal[merger_centralgal].BulgeMass;
  Mcgas=Gal[merger_centralgal].ColdGas;
  Mpstar=(Gal[p].DiskMass+Gal[p].BulgeMass);
  Mpbulge=Gal[p].BulgeMass;
  Mpgas=Gal[p].ColdGas;
  
  mass_checks("deal_with_galaxy_merger #1",p);
  mass_checks("deal_with_galaxy_merger #1",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #1",centralgal);

  /* Add the cold and stellar phase of the merged galaxy to the central one.
     Also form a bulge if BulgeFormationInMinorMergersOn is set on, but only
     with the stars from the satellite. In a major merger (dealt at the burst
     make_bulge_from_burst) all the stars in the central and satellite end up
     in the central bulge. */
  add_galaxies_together(merger_centralgal, p);

  mass_checks("deal_with_galaxy_merger #2",p);
  mass_checks("deal_with_galaxy_merger #2",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #2",centralgal);

  /* grow black hole through accretion from cold disk during mergers, as in
   * Kauffmann & Haehnelt (2000) + minor mergers - Quasar Mode */
  if(AGNrecipeOn > 0)
    grow_black_hole(merger_centralgal, mass_ratio, deltaT);

  mass_checks("deal_with_galaxy_merger #3",p);
  mass_checks("deal_with_galaxy_merger #3",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #3",centralgal);

  if (StarBurstRecipe == 0) {
    /* Starburst as in Somerville 2001, with feedback computed inside. */
    frac=collisional_starburst_recipe(mass_ratio, merger_centralgal, centralgal, time, deltaT, nstep);
    bulgesize_from_merger(mass_ratio,merger_centralgal,p,Mcstar,Mcbulge,Mcgas,
			  Mpstar,Mpbulge,Mpgas,frac);

    mass_checks("deal_with_galaxy_merger #3.5",p);
    mass_checks("deal_with_galaxy_merger #3.5",merger_centralgal);
    mass_checks("deal_with_galaxy_merger #3.5",centralgal);

    if(mass_ratio > ThreshMajorMerger)
      make_bulge_from_burst(merger_centralgal);    
  }

  mass_checks("deal_with_galaxy_merger #4",p);
  mass_checks("deal_with_galaxy_merger #4",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #4",centralgal);

  /* If we are in the presence of a minor merger, check disk stability (the disk
   * is completely destroyed in major mergers)*/
  if(TrackDiskInstability)
    if(mass_ratio < ThreshMajorMerger &&
       (Gal[merger_centralgal].DiskMass+Gal[merger_centralgal].BulgeMass) > 0.0)
      check_disk_instability(merger_centralgal);

  /* Not supported option to shrink bulge sizes in gas rich mergers */
#ifdef SHRINKINRICHMERGER  
  if (Mcgas+Mcstar+Mpgas+Mpstar > 1.e-8 ) {
    Gal[merger_centralgal].BulgeSize /= 1+pow((Mcgas+Mpgas)/(Mcgas+Mcstar+Mpgas+Mpstar)/0.15,1.);
    if (Gal[merger_centralgal].BulgeSize < 1.e-8)
      Gal[merger_centralgal].BulgeSize = 1.e-8;
  }
#endif

  if ((Gal[merger_centralgal].BulgeMass > 1.e-6 && Gal[merger_centralgal].BulgeSize == 0.0) ||
      (Gal[merger_centralgal].BulgeMass == 0.0 && Gal[merger_centralgal].BulgeSize >1.e-6)) {
    printf("central: stellarmass %f, bulgemass %f, bulgesize %f, coldgas %f,gasdisk %f,stellardisk %f \n",
    		(Gal[merger_centralgal].DiskMass+Gal[merger_centralgal].BulgeMass),Gal[merger_centralgal].BulgeMass,
    		Gal[merger_centralgal].BulgeSize,Gal[merger_centralgal].ColdGas,Gal[merger_centralgal].GasDiskRadius,
    		Gal[merger_centralgal].StellarDiskRadius);
    exit(0);
  }

  if (DiskRadiusMethod == 2) {
    get_gas_disk_radius(merger_centralgal);
    get_stellar_disk_radius(merger_centralgal);
  }

  mass_checks("deal_with_galaxy_merger #5",p);
  mass_checks("deal_with_galaxy_merger #5",merger_centralgal);
  mass_checks("deal_with_galaxy_merger #5",centralgal);

}
/**@brief  construct_galaxies() recursively runs the semi-analytic model.
  *        For each halo it checks if its main progenitor has been done, then
  *        if all the halos in the FOF of its main progenitor have been
  *        done and then runs the SAM in the current halo. This means that
  *        for the first time its called it will walk up the tree into the
  *        haloes in the earliest snapshot.
  *
  *        When it finds a halo that needs to be done it calls
  *        join_galaxies_of_progenitors and evolve_galaxies. */
void construct_galaxies(int filenr, int treenr, int halonr)
{
  static int halosdone = 0;
  int prog, fofhalo, ngal, cenngal, p;

  HaloAux[halonr].DoneFlag = 1;
  halosdone++;

  prog = Halo[halonr].FirstProgenitor;

  while(prog >= 0) //If halo has a progenitor
    {
      if(HaloAux[prog].DoneFlag == 0) //If progenitor hasn't been done yet
		construct_galaxies(filenr, treenr, prog);
      prog = Halo[prog].NextProgenitor;	//Jump to next halo in progenitors FOF
    }

  //Now check for the progenitors of all the halos in the current FOF group
  fofhalo = Halo[halonr].FirstHaloInFOFgroup;	//Starting at the first halo in current FOF
  if(HaloAux[fofhalo].HaloFlag == 0)	//If it hasn't been done
    {
      HaloAux[fofhalo].HaloFlag = 1;	//mark as to do
      while(fofhalo >= 0)	//go through all the halos in current FOF
        {
    	  prog = Halo[fofhalo].FirstProgenitor;
    	  while(prog >= 0)	//build its progenitors
    	    {
    		  if(HaloAux[prog].DoneFlag == 0)
    			construct_galaxies(filenr, treenr, prog);
    		  prog = Halo[prog].NextProgenitor;
    	    }

    	  fofhalo = Halo[fofhalo].NextHaloInFOFgroup;	//Jump to next halo in FOF
        }
    }

  /* At this point, the galaxies for all progenitors of this halo have been
   * properly constructed. Also, the galaxies of the progenitors of all other 
   * halos in the same FOF-group have been constructed as well. We can hence go
   * ahead and construct all galaxies for the subhalos in this FOF halo, and
   * evolve them in time. */


  fofhalo = Halo[halonr].FirstHaloInFOFgroup;
  if(HaloAux[fofhalo].HaloFlag == 1)	//If it is marked as an halo to do
    {
      ngal = 0;
      HaloAux[fofhalo].HaloFlag = 2;

      cenngal = set_merger_center(fofhalo);	//Find type 0 for type 1 to merge into

      /*For all the halos in the current FOF join all the progenitor galaxies together
       * ngals will be the total number of galaxies in the current FOF*/
      while(fofhalo >= 0)
        {
    	  ngal = join_galaxies_of_progenitors(fofhalo, ngal, &cenngal);
    	  fofhalo = Halo[fofhalo].NextHaloInFOFgroup;
        }


      /*Evolve the Galaxies -> SAM! */
      evolve_galaxies(Halo[halonr].FirstHaloInFOFgroup, ngal, treenr, cenngal);

      for (p =0;p<ngal;p++)
	    mass_checks("Construct_galaxies #1",p);
    }
}
/**@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;
}
void disrupt(int p, int centralgal)
{
  double rho_sat, rho_cen;
  double cen_mass, r_sat, radius;
  int outputbin, j, q;

  /* If the main halo density at the pericentre (closest point in the orbit
   * to the central galaxy)is larger than the satellite's density at the
   * half mass radius, the satellite is completely disrupted. Note that since
   * the satellite is a type 2 the only mass components remaining and
   * contributing to the density are the cold gas and stellar mass. */

  //TODO If we are passing in centralgal then we should not set it here 
  centralgal=Gal[p].CentralGal;
 
  mass_checks("Top of disrupt",centralgal);
  mass_checks("Top of disrupt",p);

  /* Radius calculated at the peri-point */
  radius=peri_radius(p, centralgal);
  if (radius < 0) {
   terminate("must be wrong \n");
  }

  /* Calculate the density of the main central halo at radius (the peri-centre).
   * The tidal forces are caused by the dark matter of the main halo, hence Mvir
   * is used. */
  cen_mass=Gal[centralgal].Mvir*radius/Gal[centralgal].Rvir;
  rho_cen=cen_mass/pow3(radius);

  /* Calculate the density of the satellite's baryonic material */
  if (Gal[p].DiskMass+Gal[p].BulgeMass>0) {
    /* Calculate the rho according to the real geometry */
    r_sat = sat_radius(p);
    /* Or use radius at the mean radius of the stellar mass */
    /* r_sat=(Gal[p].BulgeMass*Gal[p].BulgeSize+(Gal[p].StellarMass-Gal[p].BulgeMass)
     *        *Gal[p].StellarDiskRadius/3*1.68)
     *       /(Gal[p].StellarMass); */

    /* to calculate the density */
    //rho_sat=Gal[p].StellarMass/pow2(r_sat);
    rho_sat=(Gal[p].DiskMass+Gal[p].BulgeMass+Gal[p].ColdGas)/pow3(r_sat);
  }
  else
    rho_sat=0.0;

  /* If density of the main halo is larger than that of the satellite baryonic
   * component, complete and instantaneous disruption is assumed. Galaxy becomes
   * a type 3 and all its material is transferred to the central galaxy. */
  if (rho_cen > rho_sat) {
    Gal[p].Type = 3;
#ifdef GALAXYTREE      
    q = Gal[Gal[p].CentralGal].FirstProgGal;
    if (q >= 0) {
      // add progenitors of Gal[p] to the list of progentitors of Gal[p].CentralGal
      while (GalTree[q].NextProgGal >= 0)
	q = GalTree[q].NextProgGal;
	
      GalTree[q].NextProgGal = Gal[p].FirstProgGal;
      
      if(GalTree[q].NextProgGal >= NGalTree)
	    {
	      printf("q=%d p=%d GalTree[q].NextProgGal=%d NGalTree=%d\n",
		     q, p, GalTree[q].NextProgGal, NGalTree);
	      terminate("problem");
	    }
    }
    if(q < 0)
	terminate("this shouldn't happen");
	
     // TODO if !(q>=0) shouldn't we set
      // Gal[Gal[p].CentralGal].FirstProgGal to Gal[p].FirstProgGal  ??

      q = GalTree[q].NextProgGal;

      if(q < 0)
	terminate("inconsistency");

      if(HaloGal[GalTree[q].HaloGalIndex].GalTreeIndex != q)
	terminate("inconsistency");

      HaloGal[GalTree[q].HaloGalIndex].DisruptOn = 1;
#endif
    /* Put gas component to the central galaxy hot gas and stellar material into the ICM.
     * Note that the staellite should have no extended components. */
    // TODO Shouldn't the stars end up in the bulge? - this is a close merger
    transfer_gas(centralgal,"Hot",p,"Cold",1.);
    transfer_gas(centralgal,"Hot",p,"Hot",1.);
    transfer_stars(centralgal,"ICM",p,"Disk",1.);
    transfer_stars(centralgal,"ICM",p,"Bulge",1.);
    /* Add satellite's luminosity into the luminosity of the ICL
     * component of the central galaxy. */
#ifdef ICL
    for(outputbin = 0; outputbin < NOUT; outputbin++) {
      for(j = 0; j < NMAG; j++) {
#ifdef OUTPUT_REST_MAGS 
	Gal[centralgal].ICLLum[j][outputbin] += Gal[p].Lum[j][outputbin];
#endif
#ifdef COMPUTE_OBS_MAGS
	Gal[centralgal].ObsICL[j][outputbin] += Gal[p].ObsLum[j][outputbin];
#endif
      }  
    }
#endif      
  }
  mass_checks("Bottom of disrupt",centralgal);
  mass_checks("Bottom of disrupt",p);
  
}
Beispiel #9
0
/* 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 Updates cold, hot and external gas components due to SN
 *         reheating and ejection. */
void update_from_feedback(int p, int centralgal, double reheated_mass, double ejected_mass)
{
  double dis=0.;
  double massremain;
  double fraction;
  int merger_centre;

  //mass_checks("update_from_feedback #1",p);

  if(Gal[p].ColdGas > 0.)
  {
      //REHEAT
      // if galaxy is a type 1 or a type 2 orbiting a type 1 with hot gas being striped,
      //some of the reheated and ejected masses goes to the type 0 and some stays in the type 1

      if(Gal[p].Type ==0)
	{
	  transfer_gas(p,"Hot",p,"Cold",((float)reheated_mass)/Gal[p].ColdGas,"update_from_feedback", __LINE__);
	}
      else if(Gal[p].Type <3)
	{
	  if(Gal[p].Type ==1)
	    merger_centre=centralgal;
	  else if(Gal[p].Type ==2)
	    merger_centre=Gal[p].CentralGal;

	  dis=separation_gal(centralgal,Gal[p].CentralGal)/(1+ZZ[Halo[Gal[centralgal].HaloNr].SnapNum]);

	  //compute share of reheated mass
	  if (dis<Gal[centralgal].Rvir && Gal[Gal[p].CentralGal].Type == 1)
	    {
	      //mass that remains on type1 (the rest goes to type 0) for reheat - massremain, for eject - ejected mass
	      massremain=reheated_mass*Gal[p].HotRadius/Gal[p].Rvir;
	      ejected_mass = ejected_mass*Gal[p].HotRadius/Gal[p].Rvir;

	      if (massremain > reheated_mass)
		massremain = reheated_mass;
	    }
	  else
	    massremain=reheated_mass;

	  //needed due to precision issues, since we first remove massremain and then (reheated_mass-massremain)
	  //from the satellite into the type 0 and type 1 the fraction might not add up on the second call
	  //since Gal[p].ColdGas is a float and reheated_mass & massremain are doubles
	  if((massremain + reheated_mass)>Gal[p].ColdGas)
	    massremain=Gal[p].ColdGas-reheated_mass;

	  //transfer massremain
	  transfer_gas(Gal[p].CentralGal,"Hot",p,"Cold",massremain/Gal[p].ColdGas,"update_from_feedback", __LINE__);

	  //transfer reheated_mass-massremain from galaxy to the type 0
	  if (reheated_mass > massremain)
	    if(Gal[p].ColdGas > 0.) //if the reheat to itself, left cold gas below limit do not reheat to central
	      transfer_gas(centralgal,"Hot",p,"Cold",(reheated_mass-massremain)/Gal[p].ColdGas,"update_from_feedback", __LINE__);
	}//types

  }//if(Gal[p].ColdGas > 0.)

  mass_checks("update_from_feedback #2",p);

  //DO EJECTION OF GAS
  if (Gal[Gal[p].CentralGal].HotGas > 0.)
    {
      if (ejected_mass > Gal[Gal[p].CentralGal].HotGas)
	ejected_mass = Gal[Gal[p].CentralGal].HotGas;  //either eject own gas or merger_centre gas for ttype 2's

      fraction=((float)ejected_mass)/Gal[Gal[p].CentralGal].HotGas;

      if (Gal[Gal[p].CentralGal].Type == 1)
	{
	  /* If type 1, or type 2 orbiting type 1 near type 0 */
	  if (FateOfSatellitesGas == 0)
	    transfer_gas(Gal[p].CentralGal,"Ejected",Gal[p].CentralGal,"Hot",fraction,"update_from_feedback", __LINE__);
	  else if (FateOfSatellitesGas == 1)
	    {
	      if (dis < Gal[centralgal].Rvir)
		transfer_gas(centralgal,"Hot",Gal[p].CentralGal,"Hot",fraction,"update_from_feedback", __LINE__);
	      else
		transfer_gas(Gal[p].CentralGal,"Ejected",Gal[p].CentralGal,"Hot",fraction,"update_from_feedback", __LINE__);
	    }
	}
      else // If galaxy type 0 or type 2 merging into type 0
	transfer_gas(centralgal,"Ejected",Gal[p].CentralGal,"Hot",fraction,"update_from_feedback", __LINE__);

    }//(Gal[Gal[p].CentralGal].HotGas > 0.)

}
/** @brief Main recipe, calculates the fraction of cold gas turned into stars due
  *        to star formation; the fraction of mass instantaneously recycled and
  *        returned to the cold gas; the fraction of gas reheated from cold to hot,
  *        ejected from hot to external and returned from ejected to hot due to
  *        SN feedback.   */
void starformation(int p, int centralgal, double time, double dt, int nstep)
{
	/*! Variables: reff-Rdisk, tdyn=Rdisk/Vmax, strdot=Mstar_dot, stars=strdot*dt*/
  double tdyn, strdot=0., stars, cold_crit, metallicitySF;
  
  if(Gal[p].Type == 0)
    {
      tdyn = Gal[p].GasDiskRadius / Gal[p].Vmax;
      cold_crit = SfrColdCrit * Gal[p].Vmax/200. * Gal[p].GasDiskRadius*100.;
    }
  else
    {
      tdyn = Gal[p].GasDiskRadius / Gal[p].InfallVmax;
      cold_crit = SfrColdCrit * Gal[p].InfallVmax/200. * Gal[p].GasDiskRadius*100.;
    }

  //standard star formation law (Croton2006, Delucia2007, Guo2010)
  if(StarFormationModel == 0)
    {
      if(Gal[p].ColdGas > cold_crit)
	strdot = SfrEfficiency * (Gal[p].ColdGas - cold_crit) / tdyn;
      else
	strdot = 0.0;
    }

  /*if(StarFormationModel == 1)
  {
  	strdot = ALTERNATIVE STAR FORMATION LAW

  }*/

  /* Note that Units of dynamical time are Mpc/Km/s - no conversion on dt needed */
  stars = strdot * dt;
  if(stars < 0.0)
    terminate("***error stars<0.0***\n");

//otherwise cold gas and stars share material in update_stars_due_to_reheat
#ifdef FEEDBACK_COUPLED_WITH_MASS_RETURN
  if(stars > Gal[p].ColdGas)
  	stars = Gal[p].ColdGas;
#endif

  mass_checks("recipe_starform #1",p);
  mass_checks("recipe_starform #1.1",centralgal);

  /* update for star formation
   * updates Mcold, StellarMass, MetalsMcold and MetalsStellarMass
   * in Guo2010 case updates the stellar spin -> hardwired, not an option */

  /* Store the value of the metallicity of the cold phase when SF occurs */
  if (Gal[p].ColdGas > 0.)
  	metallicitySF= metals_total(Gal[p].MetalsColdGas)/Gal[p].ColdGas;
  else
    metallicitySF=0.;
 

  if (stars > 0.)
  	update_stars_due_to_reheat(p, centralgal, &stars);

  mass_checks("recipe_starform #2",p);
  mass_checks("recipe_starform #2.1",centralgal);

  /*  update the star formation rate */
   /*Sfr=stars/(dt*steps)=strdot*dt/(dt*steps)=strdot/steps -> average over the STEPS*/
   Gal[p].Sfr += stars / (dt * STEPS);


  // update_from_star_formation can only be called
  // after SD_feeedback recipe since stars need to be re_set once the reheated mass is known
  // (star formation and feedback share the same fraction of cold gas)
  if (stars > 0.)
    update_from_star_formation(p, stars, false, nstep); // false indicates not a burst

  update_massweightage(p, stars, time);


#ifndef FEEDBACK_COUPLED_WITH_MASS_RETURN
  /* ifdef FEEDBACK_COUPLED_WITH_MASS_RETURN feedback is only called
   * when stars die, inside DETAILED_METALS_AND_MASS_RETURN */
  if (stars > 0.)
    SN_feedback(p, centralgal, stars, "ColdGas");
#endif

#ifdef COMPUTE_SPECPHOT_PROPERTIES
#ifndef POST_PROCESS_MAGS
  /*  Update the luminosities due to the stars formed */
  if (stars > 0.0)
    add_to_luminosities(p, stars, time, dt, metallicitySF);
#endif //NDEF POST_PROCESS_MAGS
#endif //COMPUTE_SPECPHOT_PROPERTIES

  if(Gal[p].DiskMass > 0.0)
    check_disk_instability(p);

  if (DiskRadiusModel== 0)
    get_stellar_disk_radius(p);

}
/* there are two modes for supernova feedback corresponding to when the mass returning
 * by dying stars is returned to the cold gas - reheat and ejection; and when the mass
 * is returned to the hot gas - onle ejection.*/
void SN_feedback(int p, int centralgal, double stars, char feedback_location[])
{
  double CentralVvir, MergeCentralVvir=0., EjectVmax, EjectVvir, SN_Energy, Reheat_Energy, fac;
  double reheated_mass=0., ejected_mass=0.;
  /* SN FEEDBACK MODEL */

  /* In Guo2010 type 1s can eject, reincorporate gas and get gas from their
   * own satellites (is not sent to the type 0 galaxy as in Delucia2007),
   * for gas flow computations:
   * If satellite is inside Rvir of main halo, Vvir of main halo used
   * If it is outside, the Vvir of its central subhalo is used. */

  if (strcmp(feedback_location,"HotGas")==0)
    reheated_mass = 0.;
  else
    if (strcmp(feedback_location,"ColdGas")==0)
	{
	CentralVvir = Gal[centralgal].Vvir; // main halo Vvir
	MergeCentralVvir = Gal[Gal[p].CentralGal].Vvir; //central subhalo Vvir

	mass_checks("recipe_starform #0",p);
	mass_checks("recipe_starform #0.1",centralgal);

	// Feedback depends on the circular velocity of the host halo
	// Guo2010 - eq 18 & 19
	if(FeedbackReheatingModel == 0)
	  {
	    if (Gal[Gal[p].CentralGal].Type == 0)
	      reheated_mass = FeedbackReheatingEpsilon * stars *
	      (.5+1./pow(Gal[Gal[p].CentralGal].Vmax/ReheatPreVelocity,ReheatSlope));
	    else
	      reheated_mass = FeedbackReheatingEpsilon * stars *
	      (.5+1./pow(Gal[Gal[p].CentralGal].InfallVmax/ReheatPreVelocity,ReheatSlope));

	    if (reheated_mass * Gal[Gal[p].CentralGal].Vvir * Gal[Gal[p].CentralGal].Vvir > stars * (EtaSNcode * EnergySNcode))
	      reheated_mass = stars * (EtaSNcode * EnergySNcode) / (Gal[Gal[p].CentralGal].Vvir * Gal[Gal[p].CentralGal].Vvir);
	  }
	/*else if(FeedbackReheatingModel == 1)
	  {
	    reheated_mass =  ALTERNATIVE Reheating LAW ;
	  }*/

	if(reheated_mass > Gal[p].ColdGas)
	  reheated_mass = Gal[p].ColdGas;

	}// end if feedback_location


  /* Determine ejection (for FeedbackEjectionModel 2 we have the dependence on Vmax)
   * Guo2010 - eq 22
   * Note that satellites can now retain gas and have their own gas cycle*/

  if (Gal[Gal[p].CentralGal].Type == 0)
    {
      EjectVmax=Gal[centralgal].Vmax;
      EjectVvir=Gal[centralgal].Vvir;// main halo Vvir
    }
  else
    {
      EjectVmax=Gal[Gal[p].CentralGal].InfallVmax;
      EjectVvir=Gal[Gal[p].CentralGal].Vvir; //central subhalo Vvir
    }

  if(FeedbackEjectionModel == 0)
    {
      ejected_mass = (FeedbackEjectionEfficiency* (EtaSNcode * EnergySNcode) * stars *
	      min(1./FeedbackEjectionEfficiency, .5+1/pow(EjectVmax/EjectPreVelocity,EjectSlope)) -
	      reheated_mass*EjectVvir*EjectVvir) /(EjectVvir*EjectVvir);
    }
  else if(FeedbackEjectionModel == 1)//the ejected material is assumed to have V_SN
    {
      SN_Energy = .5 * stars * (EtaSNcode * EnergySNcode);
      Reheat_Energy = .5 * reheated_mass * EjectVvir * EjectVvir;

      ejected_mass = (SN_Energy - Reheat_Energy)/(0.5 * FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode));

      //if VSN^2<Vvir^2 nothing is ejected
      if(FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode)<EjectVvir*EjectVvir)
	ejected_mass =0.0;
    }

  // Finished calculating mass exchanges, so just check that none are negative
  if (reheated_mass < 0.0) reheated_mass = 0.0;
  if (ejected_mass < 0.0) ejected_mass = 0.0;

  /* Update For Feedback */
  /* update cold, hot, ejected gas fractions and respective metallicities
   * there are a number of changes introduced by Guo2010 concerning where
   * the gas ends up */

  //ejected_mass = 0.01*Gal[centralgal].HotGas;
  if (reheated_mass + ejected_mass > 0.)
    update_from_feedback(p, centralgal, reheated_mass, ejected_mass);
}
//void update_from_star_formation(int p, double time, double stars, double metallicity)
void update_from_star_formation(int p, double stars, bool flag_burst, int nstep)
{
  int i;
  double fraction;
  double stars_to_add=0.;

  if(Gal[p].ColdGas <= 0. || stars <= 0.) {
    printf("update_from_star_formation: Gal[p].ColdGas <= 0. || stars <= 0.\n");
    exit(0);
  }

  /* If DETAILED_METALS_AND_MASS_RETURN, no longer an assumed instantaneous
   * recycled fraction. Mass is returned over time via SNe and AGB winds.
   * Update the Stellar Spin when forming stars */
#ifndef DETAILED_METALS_AND_MASS_RETURN
  stars_to_add=(1 - RecycleFraction) * stars;
#else
  stars_to_add=stars;
#endif

  if (Gal[p].DiskMass+stars_to_add > 1.e-8)
    for (i = 0; i < 3; i++)
      Gal[p].StellarSpin[i]=((Gal[p].StellarSpin[i])*(Gal[p].DiskMass) + stars_to_add*Gal[p].GasSpin[i])/(Gal[p].DiskMass+stars_to_add);

    /*  Update Gas and Metals from star formation */
  mass_checks("update_from_star_formation #0",p);

  fraction=stars_to_add/Gal[p].ColdGas;


#ifdef STAR_FORMATION_HISTORY
  Gal[p].sfh_DiskMass[Gal[p].sfh_ibin]+=stars_to_add; //ROB: Now, all SF gas is put in SFH array ("recycled' mass will return to gas phase over time)
  Gal[p].sfh_MetalsDiskMass[Gal[p].sfh_ibin] = metals_add(Gal[p].sfh_MetalsDiskMass[Gal[p].sfh_ibin],Gal[p].MetalsColdGas,fraction);
#ifdef INDIVIDUAL_ELEMENTS
  Gal[p].sfh_ElementsDiskMass[Gal[p].sfh_ibin] = elements_add(Gal[p].sfh_ElementsDiskMass[Gal[p].sfh_ibin],Gal[p].ColdGas_elements,fraction);
#endif
#ifdef TRACK_BURST
  if (flag_burst) Gal[p].sfh_BurstMass[Gal[p].sfh_ibin]+=stars_to_add;
#endif
#endif


  Gal[p].MetalsDiskMass=metals_add(Gal[p].MetalsDiskMass,Gal[p].MetalsColdGas,fraction);
  Gal[p].MetalsColdGas=metals_add(Gal[p].MetalsColdGas,Gal[p].MetalsColdGas,-fraction);

  //GLOBAL PROPERTIES
  Gal[p].DiskMass += stars_to_add;
  Gal[p].ColdGas -= stars_to_add;
#ifdef INDIVIDUAL_ELEMENTS
  Gal[p].DiskMass_elements=elements_add(Gal[p].DiskMass_elements,Gal[p].ColdGas_elements,fraction);
  Gal[p].ColdGas_elements=elements_add(Gal[p].ColdGas_elements,Gal[p].ColdGas_elements,-fraction);
#endif
#ifdef TRACK_BURST
  if (flag_burst) Gal[p].BurstMass+=stars_to_add;
#endif

  mass_checks("update_from_star_formation #1",p);

  /* Formation of new metals - instantaneous recycling approximation - only SNII
   * Also recompute the metallicity of the cold phase.*/
#ifndef DETAILED_METALS_AND_MASS_RETURN
  /* stars used because the Yield is defined as a fraction of
   * all stars formed, not just long lived */
  Gal[p].MetalsColdGas += Yield * stars;
#endif

  if (DiskRadiusModel == 0)
    get_stellar_disk_radius(p);

}
void compute_cooling(int p, double dt, int ngal)
{
  double Vvir, Rvir, x, lambda, tcool, rcool, temp, tot_hotMass, tot_metals, HotRadius;
  double coolingGas, logZ, rho_rcool, rho0;

  mass_checks("cooling_recipe #1",p);

  tot_hotMass = Gal[p].HotGas;
  tot_metals = metals_total(Gal[p].MetalsHotGas);

  if(tot_hotMass > 1.0e-6)
  {

    Vvir = Gal[p].Vvir;
    Rvir = Gal[p].Rvir;

    tcool = Rvir / Vvir; // tcool = t_dynamical = Rvir/Vvir

    /* temp -> Temperature of the Gas in Kelvin, obtained from
     * hidrostatic equilibrium KT=0.5*mu_p*(Vc)^2 assuming Vvir~Vc */
    temp = 35.9 * Vvir * Vvir;
      
    if (Gal[p].Type == 0)
      HotRadius = Gal[p].Rvir;
    else 
      HotRadius = Gal[p].HotRadius;
    
    if(tot_metals > 0)
      logZ = log10(tot_metals / tot_hotMass);
    else
      logZ = -10.0;

    //eq. 3 and 4 Guo2010
    lambda = get_metaldependent_cooling_rate(log10(temp), logZ);
    x = PROTONMASS * BOLTZMANN * temp / lambda; // now this has units sec g/cm^3
    x /= (UnitDensity_in_cgs * UnitTime_in_s);  // now in internal units
    rho_rcool = x / (0.28086 * tcool);
    /* an isothermal density profile for the hot gas is assumed here */
    rho0 = tot_hotMass / (4 * M_PI * HotRadius);
    rcool = sqrt(rho0 / rho_rcool);
    
    if (Gal[p].CoolingRadius < rcool)
      Gal[p].CoolingRadius = rcool;
      
    //if Hotradius is used, when galaxies become type 1's there will be a discontinuity in the cooling
    if(rcool > Rvir) // INFALL DOMINATED REGIME
      //coolingGas = tot_hotMass; - Delucia 2007
      /*comes in to keep the continuity (Delucia2004) */
      coolingGas = tot_hotMass / (HotRadius / Vvir) * dt;
    else // HOT PHASE REGIME
      /*coolingGas = (tot_hotMass / Rvir) * (rcool / tcool) * dt */
      coolingGas = (tot_hotMass / HotRadius) * (rcool / tcool) * dt ;
        
    //Photoionizing background
    if (log10(temp) < 4.0)
      coolingGas = 0.;
    
    if(coolingGas > tot_hotMass)
      coolingGas = tot_hotMass;
    else if(coolingGas < 0.0)
      coolingGas = 0.0;      
    

  }
  else
  {
    coolingGas = 0.0;
  }

  Gal[p].CoolingGas = coolingGas;

  mass_checks("cooling_recipe #1.5",p);

}   
void do_AGN_heating(double dt, int ngal)
{
  double AGNrate, AGNheating, AGNaccreted, AGNcoeff, fraction, EDDrate, FreeFallRadius;
  double dist, HotGas, HotRadius, Rvir, Vvir, Mvir;
  double LeftOverEnergy, CoolingGas, AGNAccretedFromCentral;
  int p, FoFCentralGal;

  if(AGNRadioModeModel == 0)
    {
      for (p = 0; p < ngal; p++)
	if(Gal[p].Type == 0)
	  FoFCentralGal=p;
    }

  for (p = 0; p < ngal; p++)
    {
      Gal[p].CoolingRate_beforeAGN += Gal[p].CoolingGas / (dt*STEPS);

      AGNrate=0.;
      LeftOverEnergy = 0.;

      HotGas = Gal[p].HotGas;
      HotRadius = Gal[p].HotRadius;
      CoolingGas = Gal[p].CoolingGas;
      Mvir = Gal[p].Mvir;
      Rvir = Gal[p].Rvir;
      Vvir = Gal[p].Vvir;

      if(HotGas > 0.0)
	{
	  if(AGNRadioModeModel == 0)
	    AGNrate = AgnEfficiency * (UnitTime_in_s*SOLAR_MASS)/(UNITMASS_IN_G*SEC_PER_YEAR)
	              * Gal[p].BlackHoleMass/Hubble_h * (HotGas/Hubble_h) * 10.;
	  else if(AGNRadioModeModel == 2)
	    {
	      //empirical (standard) accretion recipe - Eq. 10 in Croton 2006
	      AGNrate = AgnEfficiency / (UNITMASS_IN_G / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS)
  	  		* (Gal[p].BlackHoleMass / 0.01) * pow3(Vvir / 200.0)
			* ((HotGas / HotRadius * Rvir / Mvir) / 0.1);
	    }
	  else if(AGNRadioModeModel == 3 || AGNRadioModeModel == 4)
	    {
	      double x, lambda, temp, logZ, tot_metals;

	      tot_metals = metals_total(Gal[p].MetalsHotGas);

	      /* temp -> Temperature of the Gas in Kelvin, obtained from
	       * hidrostatic equilibrium KT=0.5*mu_p*(Vc)^2 assuming Vvir~Vc */
	      temp = 35.9 * Vvir * Vvir;
	      if(tot_metals > 0)
		logZ = log10(tot_metals / HotGas);
	      else
		logZ = -10.0;
	      lambda = get_metaldependent_cooling_rate(log10(temp), logZ);
	      x = PROTONMASS * BOLTZMANN * temp / lambda; // now this has units sec g/cm^3
	      x /= (UnitDensity_in_cgs * UnitTime_in_s);  // now in internal units

	      /* Bondi-Hoyle accretion recipe -- efficiency = 0.15
	       * Eq. 29 in Croton 2006 */
	      if(AGNRadioModeModel == 3)
		AGNrate = (2.5 * M_PI * G) * (0.75 * 0.6 * x) * Gal[p].BlackHoleMass * 0.15;
	      else if(AGNRadioModeModel == 4)
		{
		  /* Cold cloud accretion recipe -- trigger: Rff = 50 Rdisk,
		   * and accretion rate = 0.01% cooling rate
		   * Eq. 25 in Croton 2006 */
		  FreeFallRadius = HotGas / (6.0 * 0.6 * x * Rvir * Vvir) /	HotRadius * Rvir;
		  if(Gal[p].BlackHoleMass > 0.0 && FreeFallRadius < Gal[p].GasDiskRadius * 50.0)
		    AGNrate = 0.0001 * CoolingGas / dt;
		  else
		    AGNrate = 0.0;
		}
	    }

	  /* Eddington rate */
	  /* Note that this assumes an efficiency of 50%
	   * - it ignores the e/(1-e) factor in L = e/(1-e) Mdot c^2 */
	  EDDrate = 1.3e48 * Gal[p].BlackHoleMass / (UnitEnergy_in_cgs / UnitTime_in_s) / 9e10;

	  /* accretion onto BH is always limited by the Eddington rate */
	  if(AGNrate > EDDrate)
	    AGNrate = EDDrate;

	  /*  accreted mass onto black hole the value of dt puts an h factor into AGNaccreted as required for code units */
	  AGNaccreted = AGNrate * dt;

	  /* cannot accrete more mass than is available! */
	  if(AGNaccreted > HotGas)
	    AGNaccreted = HotGas;

	  /*  coefficient to heat the cooling gas back to the virial temperature of the halo */
	  /*  1.34e5 = sqrt(2*eta*c^2), eta=0.1 (standard efficiency) and c in km/s
	   *  Eqs. 11 & 12 in Croton 2006 */
	  AGNcoeff = (1.34e5 / Vvir) * (1.34e5 / Vvir);

	  /*  cooling mass that can be suppressed from AGN heating */
	  AGNheating = AGNcoeff * AGNaccreted;


	  if(AGNRadioModeModel == 0 && Gal[p].Type==1)
	    {
	      if(dist < Gal[FoFCentralGal].Rvir)
		{
		  if(AGNheating > (Gal[p].CoolingGas + Gal[FoFCentralGal].CoolingGas))
		    {
		      AGNheating = (Gal[p].CoolingGas + Gal[FoFCentralGal].CoolingGas);
		      AGNaccreted = (Gal[p].CoolingGas + Gal[FoFCentralGal].CoolingGas) / AGNcoeff;
		    }
		  if(AGNheating > Gal[p].CoolingGas)
		    LeftOverEnergy = AGNheating - Gal[p].CoolingGas;
		}
	    }
	  else
	    if(AGNheating > Gal[p].CoolingGas)
	      AGNaccreted = Gal[p].CoolingGas / AGNcoeff;

	  /* limit heating to cooling rate */
	  if(AGNheating > Gal[p].CoolingGas)
	    AGNheating = Gal[p].CoolingGas;




	  /*  accreted mass onto black hole */
	  Gal[p].BlackHoleMass += AGNaccreted; //ROB: transfer_mass functions should be used here
	  Gal[p].RadioAccretionRate += AGNaccreted / (dt*STEPS);
	  fraction=AGNaccreted/Gal[p].HotGas;
	  Gal[p].HotGas -= AGNaccreted;
	  Gal[p].MetalsHotGas = metals_add(Gal[p].MetalsHotGas,Gal[p].MetalsHotGas, -fraction);

#ifdef INDIVIDUAL_ELEMENTS
	  Gal[p].HotGas_elements = elements_add(Gal[p].HotGas_elements,Gal[p].HotGas_elements,-fraction);
#endif
#ifdef METALS_SELF
	  Gal[p].MetalsHotGasSelf = 	metals_add(Gal[p].MetalsHotGasSelf,Gal[p].MetalsHotGasSelf,-fraction);
#endif	

	}
      else
	AGNheating = 0.0;


      Gal[p].CoolingGas -= AGNheating;

      if(Gal[p].CoolingGas < 0.0)
	Gal[p].CoolingGas = 0.0;

      Gal[p].CoolingRate += Gal[p].CoolingGas / (dt*STEPS);

      if(AGNRadioModeModel == 0 && LeftOverEnergy>0.)
  	{
	  Gal[FoFCentralGal].CoolingGas -= LeftOverEnergy;

	  if(Gal[FoFCentralGal].CoolingGas < 0.0)
	    Gal[FoFCentralGal].CoolingGas = 0.0;
	  else
	    Gal[FoFCentralGal].CoolingRate -= LeftOverEnergy / (dt*STEPS);
  	}


      mass_checks("cooling_recipe #2.",p);

  }
}
/** @brief Main recipe, calculates the fraction of cold gas turned into stars due
  *        to star formation; the fraction of mass instantaneously recycled and
  *        returned to the cold gas; the fraction of gas reheated from cold to hot,
  *        ejected from hot to external and returned from ejected to hot due to
  *        SN feedback.   */
void starformation_and_feedback(int p, int centralgal, double time, double dt, int nstep) 
{
	/*! Variables: reff-Rdisk, tdyn=Rdisk/Vmax, strdot=Mstar_dot, stars=strdot*dt*/
  double tdyn, strdot, stars, reheated_mass, ejected_mass, fac, cold_crit,
         metallicitySF, CentralVvir, MergeCentralVvir, EjectVmax, EjectVvir,
         SN_Energy, Reheat_Energy;

  
  //standard star formation law (Croton2006, Delucia2007, Guo2010)
  if(StarFormationRecipe == 0)
  {
  	if(Gal[p].Type == 0)
  		tdyn = Gal[p].GasDiskRadius / Gal[p].Vmax;
  	else
  		tdyn = Gal[p].GasDiskRadius / Gal[p].InfallVmax;

  	if(Gal[p].Type == 0)
  		cold_crit = 0.19 * Gal[p].Vmax * Gal[p].GasDiskRadius;
	  else
	  	cold_crit = 0.19 * Gal[p].InfallVmax * Gal[p].GasDiskRadius;

  	if(Gal[p].ColdGas > cold_crit)
  		strdot = SfrEfficiency * (Gal[p].ColdGas - cold_crit) / tdyn * pow(Gal[p].Vvir / SfrLawPivotVelocity, SfrLawSlope);
  	else
  		strdot = 0.0;
  }

  //No dependce on Tdyn
  if(StarFormationRecipe == 1)
    {

	  if(Gal[p].ColdGas > 1.e-7)
		strdot = SfrEfficiency * (Gal[p].ColdGas) / (2.e-5) * pow(Gal[p].Vvir / SfrLawPivotVelocity, SfrLawSlope);
	  else
		strdot = 0.0;
    }

#ifdef H2FORMATION
  /* use H2 formation model from Krumholz */
  Not yet implemented
  H2Mass=cal_H2(p);
  strdot = SfrEfficiency * H2Mass / tdyn;
#endif    

  /*TODO - Note that Units of dynamical time are Mpc/Km/s - no conversion on dt needed
   *       be mentioned 3.06e19 to 3.15e19 */
  stars = strdot * dt;
  if(stars < 0.0)
    terminate("***error stars<0.0***\n");

/* SN FEEDBACK RECIPES */

  /* In Guo2010 type 1s can eject, reincorporate gas and get gas from their
   * own satellites (is not sent to the type 0 galaxy as in Delucia2007),
   * for gas flow computations:
   * If satellite is inside Rvir of main halo, Vvir of main halo used
   * If it is outside, the Vvir of its central subhalo is used. */

  CentralVvir = Gal[centralgal].Vvir; // main halo Vvir
  MergeCentralVvir = Gal[Gal[p].CentralGal].Vvir; //central subhalo Vvir
   
  mass_checks("recipe_starform #0",p);
  mass_checks("recipe_starform #0.1",centralgal);

  /* Feedback depends on the circular velocity of the host halo
   * Guo2010 - eq 18 & 19*/
  if(FeedbackRecipe == 0) {
    if (Gal[Gal[p].CentralGal].Type == 0)
      reheated_mass = FeedbackReheatingEpsilon * stars*
	(.5+1./pow(Gal[Gal[p].CentralGal].Vmax/ReheatPreVelocity,ReheatSlope));
    else
      reheated_mass = FeedbackReheatingEpsilon * stars*
	(.5+1./pow(Gal[Gal[p].CentralGal].InfallVmax/ReheatPreVelocity,ReheatSlope));
  }

  //Make sure that the energy used in reheat does not exceed the SN energy (central subhalo Vvir used)
  if (FeedbackRecipe == 0 || FeedbackRecipe == 1) {
    if (reheated_mass * Gal[Gal[p].CentralGal].Vvir * Gal[Gal[p].CentralGal].Vvir > stars * (EtaSNcode * EnergySNcode))
      reheated_mass = stars * (EtaSNcode * EnergySNcode) / (Gal[Gal[p].CentralGal].Vvir * Gal[Gal[p].CentralGal].Vvir);
  }

  /*  cant use more cold gas than is available! so balance SF and feedback */
  if((stars + reheated_mass) > Gal[p].ColdGas) {
    fac = Gal[p].ColdGas / (stars + reheated_mass);
    stars *= fac;
    reheated_mass *= fac;
  }  

  /* Determine ejection (for FeedbackRecipe 2 we have the dependence on Vmax)
   * Guo2010 - eq 22
   * Note that satellites can now retain gas and have their own gas cycle*/

  if (Gal[Gal[p].CentralGal].Type == 0)
    {
	  EjectVmax=Gal[centralgal].Vmax;
	  EjectVvir=Gal[centralgal].Vvir;// main halo Vvir
    }
  else
    {
	  EjectVmax=Gal[Gal[p].CentralGal].InfallVmax;
	  EjectVvir=Gal[Gal[p].CentralGal].Vvir; //central subhalo Vvir
    }

  if(FeedbackRecipe == 0)
    {
      ejected_mass =
    	(FeedbackEjectionEfficiency* (EtaSNcode * EnergySNcode) * stars *
	     min(1./FeedbackEjectionEfficiency, .5+1/pow(EjectVmax/EjectPreVelocity,EjectSlope)) -
	     reheated_mass*EjectVvir*EjectVvir) /(EjectVvir*EjectVvir);
    }
  else if(FeedbackRecipe == 1)//the ejected material is assumed to have V_SN
    {
	 
	  SN_Energy = .5 * stars * (EtaSNcode * EnergySNcode);
	  Reheat_Energy = .5 * reheated_mass * EjectVvir * EjectVvir;
	  
	  ejected_mass = (SN_Energy - Reheat_Energy)/(0.5 * FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode));

	  //if VSN^2<Vvir^2 nothing is ejected
	  if(FeedbackEjectionEfficiency*(EtaSNcode * EnergySNcode)<EjectVvir*EjectVvir)
	  		ejected_mass =0.0;
     }
    
  // Finished calculating mass exchanges, so just check that none are negative
  if (reheated_mass < 0.0) reheated_mass = 0.0;
  if (ejected_mass < 0.0) ejected_mass = 0.0;	 	  

  /*  update the star formation rate */
#ifdef SAVE_MEMORY
  /*Sfr=stars/(dt*steps)=strdot*dt/(dt*steps)=strdot/steps -> average over the STEPS*/
  Gal[p].Sfr += stars / (dt * STEPS);
#else
  for(outputbin = 0; outputbin < NOUT; outputbin++) {
    if(Halo[halonr].SnapNum == ListOutputSnaps[outputbin]) {
      Gal[p].Sfr[outputbin] += stars / (dt * STEPS);
      break;
    }
  }
#endif
 
  mass_checks("recipe_starform #1",p);
  mass_checks("recipe_starform #1.1",centralgal);

  /* update for star formation
   * updates Mcold, StellarMass, MetalsMcold and MetalsStellarMass
   * in Guo2010 case updates the stellar spin -> hardwired, not an option */

  /* Store the value of the metallicity of the cold phase when SF occurs */
  if (Gal[p].ColdGas > 0.)
#ifdef METALS
    //metallicitySF=Gal[p].MetalsColdGas.type2/Gal[p].ColdGas;
	metallicitySF= metals_total(Gal[p].MetalsColdGas)/Gal[p].ColdGas;
#else
    metallicitySF=Gal[p].MetalsColdGas/Gal[p].ColdGas;
#endif
  else