void cool_gas_onto_galaxy(int p, double dt)
{
  double fraction,Mdisk,Mcool;
  int i;

  /** @brief cool_gas_onto_galaxy updates the fractions of hot and cold gas
    * due to cooling. This is done for the mass, metals and, after Guo2010,
    * spin components */

  Mdisk=Gal[p].ColdGas;
  Mcool=Gal[p].CoolingGas;

  if (Mcool>Gal[p].HotGas)
  	Mcool = Gal[p].HotGas;

  /*  add the fraction 1/STEPS of the total cooling gas to the cold disk */
  if(Mcool > 0.0)
  {
  	//determine the xray luminosity of any cooling gas in this snapshot (White & Frenk 1991 eq21)
  	Gal[p].XrayLum = log10(2.5 * (Mcool / dt) * 6.31 * Gal[p].Vvir * Gal[p].Vvir) + 35.0;

    // We already know that 0<mcool<=Gal[p].HotGas
    fraction=((float)Mcool)/Gal[p].HotGas;
    transfer_gas(p,"Cold",p,"Hot",fraction,"cool_gas_onto_galaxy", __LINE__);

    if (DiskRadiusModel == 0)
    {
      if (Gal[p].ColdGas != 0.0)
      	for (i=0;i<3;i++)
      		Gal[p].GasSpin[i]=(Gal[p].GasSpin[i]*Mdisk+Gal[p].HaloSpin[i]*Mcool)/(Gal[p].ColdGas);
      get_gas_disk_radius(p);
    }
  }
  else
  	Gal[p].XrayLum = 0.0;
}
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
}
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);
  
}
/** @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.)

}