void make_bulge_from_burst(int p) 
{
  int outputbin, j;

  /* generate bulge */
  transfer_stars(p,"Bulge",p,"Disk",1.);

  /*  update the star formation rate */
#ifdef SAVE_MEMORY
  Gal[p].SfrBulge  = Gal[p].Sfr;
#else
  for(outputbin = 0; outputbin < NOUT; outputbin++)
    Gal[p].SfrBulge[outputbin] += Gal[p].Sfr[outputbin];
#endif

#ifndef  POST_PROCESS_MAGS
#ifdef OUTPUT_REST_MAGS
  for(outputbin = 0; outputbin < NOUT; outputbin++) {
    for(j = 0; j < NMAG; j++) {
      Gal[p].LumBulge[j][outputbin]  = Gal[p].Lum[j][outputbin];
      Gal[p].YLumBulge[j][outputbin] = Gal[p].YLum[j][outputbin];
    }
  }
#endif
#ifdef COMPUTE_OBS_MAGS
  for(outputbin = 0; outputbin < NOUT; outputbin++) {
    for(j = 0; j < NMAG; j++) {
      Gal[p].ObsLumBulge[j][outputbin]   = Gal[p].ObsLum[j][outputbin];
      Gal[p].ObsYLumBulge[j][outputbin]  = Gal[p].ObsYLum[j][outputbin];
#ifdef OUTPUT_MOMAF_INPUTS
      Gal[p].dObsLumBulge[j][outputbin]  = Gal[p].dObsLum[j][outputbin];
      Gal[p].dObsYLumBulge[j][outputbin] = Gal[p].dObsYLum[j][outputbin];
#endif
    }
  }
#endif
#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);
  
}
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
}
/** @brief Checks for disk stability using the
 *         Mo, Mao & White (1998) criteria */
void check_disk_instability(int p)
{

  double Mcrit, fraction, stars, diskmass;

/** @brief Calculates the stability of the stellar disk as discussed
 *         in Mo, Mao & White (1998). For unstable stars, the required
 *         amount is transfered to the bulge to make the disk stable again.
 *         Mass, metals and luminosities updated. After Guo2010 the bulge
 *         size is followed and needs to be updated.
 *         Eq 34 & 35 in Guo2010 are used. */


  if(DiskInstabilityModel == 0)
    {
      /* check stellar disk -> eq 34 Guo2010*/
      if (Gal[p].Type != 0)
	Mcrit = Gal[p].InfallVmax * Gal[p].InfallVmax * Gal[p].StellarDiskRadius / G;
      else
	Mcrit = Gal[p].Vmax * Gal[p].Vmax * Gal[p].StellarDiskRadius / G;
      diskmass = Gal[p].DiskMass;
      stars = diskmass - Mcrit;
      fraction = stars / diskmass;
    }
  else if (DiskInstabilityModel == 1)
    stars = 0.;

  /* add excess stars to the bulge */
  if(stars > 0.0)
    {
      /* to calculate the bulge size */
      update_bulge_from_disk(p,stars);
      transfer_stars(p,"Bulge",p,"Disk",fraction);

      if(BHGrowthInDiskInstabilityModel == 1)
	if(Gal[p].ColdGas > 0.)
	  {
	    Gal[p].BlackHoleMass += Gal[p].ColdGas*fraction;
	    Gal[p].ColdGas -= Gal[p].ColdGas*fraction;
	  }

#ifndef POST_PROCESS_MAGS
      double Lumdisk;
      int outputbin, j;
#ifdef OUTPUT_REST_MAGS
      for(outputbin = 0; outputbin < NOUT; outputbin++)
	{
	  for(j = 0; j < NMAG; j++)
	    {
	      Lumdisk = Gal[p].Lum[j][outputbin]-Gal[p].LumBulge[j][outputbin];
	      Gal[p].LumBulge[j][outputbin] += fraction * Lumdisk;
	      Lumdisk = Gal[p].YLum[j][outputbin]-Gal[p].YLumBulge[j][outputbin];
	      Gal[p].YLumBulge[j][outputbin] += fraction * Lumdisk;
	    }
	}
#endif
#ifdef COMPUTE_OBS_MAGS
      for(outputbin = 0; outputbin < NOUT; outputbin++)
	{
	  for(j = 0; j < NMAG; j++)
	    {
	      Lumdisk = Gal[p].ObsLum[j][outputbin]-Gal[p].ObsLumBulge[j][outputbin];
	      Gal[p].ObsLumBulge[j][outputbin] += fraction * Lumdisk;
	      Lumdisk = Gal[p].ObsYLum[j][outputbin]-Gal[p].ObsYLumBulge[j][outputbin];
	      Gal[p].ObsYLumBulge[j][outputbin] += fraction * Lumdisk;
#ifdef OUTPUT_MOMAF_INPUTS
	      Lumdisk = Gal[p].dObsLum[j][outputbin]-Gal[p].dObsLumBulge[j][outputbin];
	      Gal[p].dObsLumBulge[j][outputbin] += fraction * Lumdisk;
	      Lumdisk = Gal[p].dObsYLum[j][outputbin]-Gal[p].dObsYLumBulge[j][outputbin];
	      Gal[p].dObsYLumBulge[j][outputbin] += fraction * Lumdisk;
#endif
	    }
	}
#endif
#endif

      if ((Gal[p].BulgeMass > 1e-9 && Gal[p].BulgeSize == 0.0)||
	  (Gal[p].BulgeMass == 0.0 && Gal[p].BulgeSize >1e-9))
	{
	  char sbuf[1000];
	  sprintf(sbuf, "bulgesize wrong in diskinstablility.c \n");
	  terminate(sbuf);
	}
    }// if(stars > 0.0)
  
}