//Age in Mpc/Km/s/h - code units
void update_massweightage(int p, double stars, double time)
{
  int outputbin;
  double age;

  for(outputbin = 0; outputbin < NOUT; outputbin++)
    {
      age = time - NumToTime(ListOutputSnaps[outputbin]);
#ifdef DETAILED_METALS_AND_MASS_RETURN
	   	Gal[p].MassWeightAge[outputbin] += age * stars;
#else
	   	Gal[p].MassWeightAge[outputbin] += age * stars * (1. - RecycleFraction);
#endif
    }
}
Ejemplo n.º 2
0
void write_sfh_bins()
{
	FILE* SFH_Bins_File;
	struct SFH_Time *sfh_times;
	char buf[1000];

	/*
	sprintf(buf, "%s/SFH_Bins.csv", FinalOutputDir);
	if(!(SFH_Bins_File = fopen(buf, "w")))
	{
	  char sbuf[1000];
	  sprintf(sbuf, "can't open file `%s'\n", buf);
	  terminate(sbuf);
	} else
	  printf("writing sfh bins to %s\n", buf);
*/

  int snap,j, nbins,ibin;
  nbins = 0;
  for(snap = 0; snap < MAXSNAPS; snap++)
  {
	  for(j=0;j < SFH_ibin[snap][0];j++)
	  {
		  nbins++;
		  // TODO writing as CSV is temporary test for checking output in binary
/*
		  fprintf(SFH_Bins_File,"%d,%d,%f,%f,%f,%f,%d,%d\r\n",
     			snap,j,SFH_t[snap][0][j],SFH_dt[snap][0][j],
     	 	    (SFH_t[snap][0][j]+SFH_dt[snap][0][j]/2.-NumToTime(snap))*UnitTime_in_years/Hubble_h,
     	 	    SFH_dt[snap][0][j]*UnitTime_in_years/Hubble_h,
     			SFH_Nbins[snap][0][j],SFH_ibin[snap][0]);
*/
	  }
  }
//  fflush(SFH_Bins_File);
//  fclose(SFH_Bins_File);

  sfh_times = (struct SFH_Time *) mymalloc("sfh_times", sizeof(struct SFH_Time) * nbins);
  ibin = 0;
  for(snap = 0; snap < MAXSNAPS; snap++)
  {
	  for(j=0;j < SFH_ibin[snap][0];j++)
	  {
		  sfh_times[ibin].snapnum = snap;
		  sfh_times[ibin].bin = j;
		  sfh_times[ibin].lookbacktime = (SFH_t[snap][0][j]+SFH_dt[snap][0][j]/2.-NumToTime(snap))*UnitTime_in_years/Hubble_h;
		  sfh_times[ibin].dt=SFH_dt[snap][0][j]*UnitTime_in_years/Hubble_h;
		  sfh_times[ibin].nbins = SFH_Nbins[snap][0][j];
		  ibin++;
	  }
  }
	sprintf(buf, "%s/SFH_Bins", FinalOutputDir);
	if(!(SFH_Bins_File = fopen(buf, "w")))
	{
	  char sbuf[1000];
	  sprintf(sbuf, "can't open file `%s'\n", buf);
	  terminate(sbuf);
	} else
	  printf("writing sfh bins to %s\n", buf);

	// write # bins
    myfwrite(&nbins, sizeof(int), 1, SFH_Bins_File);	// write 1
	// skip header
	myfseek(SFH_Bins_File, sizeof(struct SFH_Time), SEEK_SET);
    myfwrite(sfh_times, sizeof(struct SFH_Time), nbins, SFH_Bins_File);	// size of an output structure (Galaxy_Output)
    fflush(SFH_Bins_File);
    fclose(SFH_Bins_File);


}
Ejemplo n.º 3
0
void prepare_galaxy_for_output(int n, struct GALAXY *g, struct GALAXY_OUTPUT *o)
#endif
{
  int j,ibin;

#ifndef NO_PROPS_OUTPUTS
  o->Type = g->Type;
  o->SnapNum = g->SnapNum;
  o->CentralMvir = get_virial_mass(Halo[g->HaloNr].FirstHaloInFOFgroup);
  o->CentralRvir = get_virial_radius(Halo[g->HaloNr].FirstHaloInFOFgroup);
  o->Mvir = g->Mvir;
  o->Rvir = g->Rvir;
  o->Vvir = g->Vvir;

  for(j = 0; j < 3; j++)
    {
	  o->Pos[j] = g->Pos[j];
	  o->DistanceToCentralGal[j] = wrap(Halo[Halo[g->HaloNr].FirstHaloInFOFgroup].Pos[j] - g->Pos[j],BoxSize);;
    }

  o->ColdGas = g->ColdGas;
  o->DiskMass = g->DiskMass;
  o->BulgeMass = g->BulgeMass;
  o->HotGas = g->HotGas;
  o->BlackHoleMass = g->BlackHoleMass;
#endif


#ifdef COMPUTE_SPECPHOT_PROPERTIES
#ifndef POST_PROCESS_MAGS
#ifdef OUTPUT_REST_MAGS 
  /* Luminosities are converted into Mags in various bands */
  for(j = 0; j < NMAG; j++)
 	o->Mag[j] = lum_to_mag(g->Lum[j][n]);
#endif
#endif //ndef POST_PROCESS_MAGS
#endif //COMPUTE_SPECPHOT_PROPERTIES

#ifndef LIGHT_OUTPUT
  
#ifndef NO_PROPS_OUTPUTS
#ifdef GALAXYTREE
  o->HaloID = HaloIDs[g->HaloNr].HaloID;
  o->Redshift = ZZ[g->SnapNum];

  int ii = (int) floor(o->Pos[0] * ScaleFactor);
  int jj = (int) floor(o->Pos[1] * ScaleFactor);
  int kk = (int) floor(o->Pos[2] * ScaleFactor);

  o->PeanoKey = peano_hilbert_key(ii, jj, kk, Hashbits);

  o->SubID = calc_big_db_subid_index(g->SnapNum, Halo[g->HaloNr].FileNr, Halo[g->HaloNr].SubhaloIndex);

  int tmpfirst = Halo[g->HaloNr].FirstHaloInFOFgroup;
  int lenmax = 0;
  int next = tmpfirst;
  while(next != -1)
    {
      if(Halo[next].Len > lenmax)
	{
	  lenmax = Halo[next].Len;
	  tmpfirst = next;
	}
      next = Halo[next].NextHaloInFOFgroup;
    }

  o->MMSubID = calc_big_db_subid_index(g->SnapNum, Halo[tmpfirst].FileNr, Halo[tmpfirst].SubhaloIndex);
#endif

  o->LookBackTimeToSnap = NumToTime(g->SnapNum)*UnitTime_in_years/Hubble_h;
  o->InfallVmax = g->InfallVmax;
  o->InfallSnap = g->InfallSnap;
  o-> InfallHotGas = g-> InfallHotGas;
  o->HotRadius =  g->HotRadius;
#ifdef HALOPROPERTIES
  o->HaloM_Mean200 = g->HaloM_Mean200;
  o->HaloM_Crit200 = g->HaloM_Crit200;
  o->HaloM_TopHat = g->HaloM_TopHat;
  o->HaloVelDisp = g->HaloVelDisp;
  o->HaloVmax = g->HaloVmax;
#endif

  o->Len = g->Len;
  o->Vmax = g->Vmax;

  o->BulgeSize = g->BulgeSize;
  o->EjectedMass = g->EjectedMass;
  o->BlackHoleGas = g->BlackHoleGas;

  for(j = 0; j < 3; j++)
    {
      o->Vel[j] = g->Vel[j];
#ifdef HALOSPIN
      o->HaloSpin[j] = g->HaloSpin[j];
#endif
#ifndef H2_AND_RINGS
      o->GasSpin[j] = g->GasSpin[j];
      o->StellarSpin[j] = g->StellarSpin[j];
#else
      o->DiskSpin[j] = g->DiskSpin[j];
#endif
#ifdef HALOPROPERTIES
      o->HaloPos[j] = g->HaloPos[j];
      o->HaloVel[j] = g->HaloVel[j];
      o->HaloSpin[j] = g->HaloSpin[j];
#endif      
    }

  o->XrayLum = g->XrayLum;
  o->GasDiskRadius = g->GasDiskRadius;
  o->StellarDiskRadius = g->StellarDiskRadius;
  o->CoolingRadius = g->CoolingRadius;
  o->ICM = g->ICM;
  //o->MetalsICM = CORRECTDBFLOAT(g->MetalsICM);
  o->MetalsICM = g->MetalsICM;
  o->QuasarAccretionRate = g->QuasarAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS;
  o->RadioAccretionRate = g->RadioAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS;
  o->CosInclination = g->CosInclination;

  if(g->Type == 2 || (g->Type == 1 && g->MergeOn == 1)) {
    o->OriMergTime=g->OriMergTime;
    o->MergTime = g->MergTime;
  }
  else {
    o->OriMergTime=0.0;
    o->MergTime = 0.0;
  }


#ifndef GALAXYTREE
  o->HaloIndex = g->HaloNr;
#endif
#ifdef MBPID
  o->MostBoundID = g->MostBoundID;
#endif


#ifdef GALAXYTREE
  o->DisruptOn = g->DisruptOn;
#endif
#ifdef MERGE01
  o->MergeOn = g->MergeOn;
#endif


//METALS

  /*o->MetalsColdGas = CORRECTDBFLOAT(g->MetalsColdGas);
  o->MetalsDiskMass = CORRECTDBFLOAT(g->MetalsDiskMass);
  o->MetalsBulgeMass = CORRECTDBFLOAT(g->MetalsBulgeMass);
  o->MetalsHotGas = CORRECTDBFLOAT(g->MetalsHotGas);
  o->MetalsEjectedMass = CORRECTDBFLOAT(g->MetalsEjectedMass);   
#ifdef METALS_SELF
  o->MetalsHotGasSelf = CORRECTDBFLOAT(g->MetalsHotGasSelf);
#endif*/
  o->MetalsColdGas = g->MetalsColdGas;
  o->MetalsDiskMass = g->MetalsDiskMass;
  o->MetalsBulgeMass = g->MetalsBulgeMass;
  o->MetalsHotGas = g->MetalsHotGas;
  o->MetalsEjectedMass = g->MetalsEjectedMass;
#ifdef METALS_SELF
  o->MetalsHotGasSelf = g->MetalsHotGasSelf;
#endif
#ifdef TRACK_BURST
  o->BurstMass=g->BurstMass;
#endif

#ifdef H2_AND_RINGS
  for(j=0; j<RNUM; j++)
  {
  	o->H2fractionr[j] = g -> H2fractionr[j];
  	o->ColdGasr[j] = g->ColdGasr[j];
  	o->DiskMassr[j] = g->DiskMassr[j];
  	o->MetalsColdGasr[j] = g->MetalsColdGasr[j];
  	o->MetalsDiskMassr[j] = g->MetalsDiskMassr[j];
  }
#endif

 //STAR FORMATION HISTORIES / RATES

#ifdef STAR_FORMATION_HISTORY
  o->sfh_ibin=g->sfh_ibin;
  ibin=0;
  for (j=0;j<=o->sfh_ibin;j++) {

#ifndef NORMALIZEDDB
// 	  o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.-NumToTime(g->SnapNum))*UnitTime_in_years/Hubble_h; //Time from middle of this sfh bin to snapshot - converted from code units to years
 	  //o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.)*UnitTime_in_years/Hubble_h; //ROB: Lookback time to middle of SFH bin, in years //ROB: Now use LookBackTimeToSnap + sfh_time instead.
// 	  o->sfh_dt[j]=g->sfh_dt[j]*UnitTime_in_years/Hubble_h;
 	  o->sfh_DiskMass[j]=g->sfh_DiskMass[j];
 	  o->sfh_BulgeMass[j]=g->sfh_BulgeMass[j];
 	  o->sfh_ICM[j]=g->sfh_ICM[j];
 	  o->sfh_MetalsDiskMass[j]=g->sfh_MetalsDiskMass[j];
 	  o->sfh_MetalsBulgeMass[j]=g->sfh_MetalsBulgeMass[j];
 	  o->sfh_MetalsICM[j]=g->sfh_MetalsICM[j];
	  //#ifdef DETAILED_METALS_AND_MASS_RETURN
#ifdef INDIVIDUAL_ELEMENTS
	  o->sfh_ElementsDiskMass[j]=g->sfh_ElementsDiskMass[j];
	  o->sfh_ElementsBulgeMass[j]=g->sfh_ElementsBulgeMass[j];
	  o->sfh_ElementsICM[j]=g->sfh_ElementsICM[j];
#endif
	  //#endif
#ifdef TRACK_BURST
	  o->sfh_BurstMass[j]=g->sfh_BurstMass[j];
#endif
#else // NORMALIZEDDB
	  sfh_bin[j].sfh_DiskMass = g->sfh_DiskMass[j];
	  sfh_bin[j].sfh_BulgeMass = g->sfh_BulgeMass[j];
	  sfh_bin[j].sfh_ICM = g->sfh_ICM[j];
	  sfh_bin[j].sfh_MetalsDiskMass = g->sfh_MetalsDiskMass[j];
	  sfh_bin[j].sfh_MetalsBulgeMass = g->sfh_MetalsBulgeMass[j];
	  sfh_bin[j].sfh_MetalsICM = g->sfh_MetalsICM[j];
	  sfh_bin[j].sfh_ibin = j;
	  sfh_bin[j].snapnum = g->SnapNum;
	  sfh_bin[j].GalID = -1; // TODO must be reset
#endif // NORMALIZEDDB
   }

  //Set all non-used array elements to zero:
  // important if we want to read files in database that all values are valid SQLServer floats
  for (j=o->sfh_ibin+1;j<SFH_NBIN;j++) {
#ifndef NORMALIZEDDB
//	  o->sfh_time[j]=0.;
//	  o->sfh_dt[j]=0.;
	  o->sfh_DiskMass[j]=0.;
	  o->sfh_BulgeMass[j]=0.;
	  o->sfh_ICM[j]=0.;
	  o->sfh_MetalsDiskMass[j]=metals_init();
	  o->sfh_MetalsBulgeMass[j]=metals_init();
	  o->sfh_MetalsICM[j]=metals_init();
#ifdef INDIVIDUAL_ELEMENTS
	  o->sfh_ElementsDiskMass[j]=elements_init();
	  o->sfh_ElementsBulgeMass[j]=elements_init();
	  o->sfh_ElementsICM[j]=elements_init();
#endif
#ifdef TRACK_BURST
	  o->sfh_BurstMass[j]=0.;
#endif
#else
	  sfh_bin[j].sfh_DiskMass=0;
	  sfh_bin[j].sfh_BulgeMass=0;
	  sfh_bin[j].sfh_ICM=0;
	  sfh_bin[j].sfh_ibin = 0;
	  sfh_bin[j].snapnum = g->SnapNum;
	  // TODO other elements not important, are not being written anyway. Or are they used elsewhere?
#endif
  }
#endif //STAR_FORMATION_HISTORY

#ifdef INDIVIDUAL_ELEMENTS
  /*for (j=0;j<ELEMENT_NUM;j++)
  {
	  o->DiskMass_elements[j]=g->DiskMass_elements[j];
	  o->BulgeMass_elements[j]=g->BulgeMass_elements[j];
	  o->ColdGas_elements[j]=g->ColdGas_elements[j];
	  o->HotGas_elements[j]=g->HotGas_elements[j];
	  o->EjectedMass_elements[j]=g->EjectedMass_elements[j];
	  o->ICM_elements[j]=g->ICM_elements[j];
  }*/

  /*o->DiskMass_elements = CORRECTDBFLOAT(g->DiskMass_elements);
  o->BulgeMass_elements = CORRECTDBFLOAT(g->BulgeMass_elements);
  o->ColdGas_elements = CORRECTDBFLOAT(g->ColdGas_elements);
  o->HotGas_elements = CORRECTDBFLOAT(g->HotGas_elements);
  o->ICM_elements = CORRECTDBFLOAT(g->ICM_elements);*/
  o->DiskMass_elements = g->DiskMass_elements;
  o->BulgeMass_elements = g->BulgeMass_elements;
  o->ColdGas_elements = g->ColdGas_elements;
  o->HotGas_elements = g->HotGas_elements;
  o->EjectedMass_elements = g->EjectedMass_elements;
  o->ICM_elements = g->ICM_elements;
#endif

  o->PrimordialAccretionRate = CORRECTDBFLOAT(g->PrimordialAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->CoolingRate = CORRECTDBFLOAT(g->CoolingRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->CoolingRate_beforeAGN = CORRECTDBFLOAT(g->CoolingRate_beforeAGN * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);

 //NOTE: in Msun/yr
#ifdef SAVE_MEMORY
  o->Sfr = CORRECTDBFLOAT(g->Sfr * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
 #ifdef H2_AND_RINGS
  for(j=0; j<RNUM; j++) o->Sfrr[j] = g->Sfrr[j] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS;  
#endif
#else
  o->Sfr = CORRECTDBFLOAT(g->Sfr[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
#endif 

#endif //NO_PROPS_OUTPUTS


//MAGNITUDES
#ifdef COMPUTE_SPECPHOT_PROPERTIES
#ifdef POST_PROCESS_MAGS

  /*   int N_vespa_files=29, N_vespa_AgeBins=16;
       double vespa_age[17]={0.000125893, 0.02000, 0.03000, 0.04800, 0.07400, 0.11500,
                          0.17700, 0.27500, 0.42500, 0.65800, 1.02000, 1.57000,
                          2.44000, 3.78000, 5.84000, 9.04000, 14.0000};
       int vespa_sfh_IDs[29]={0,   1, 12, 16,  2, 22, 23, 27, 29, 36,
       		               42, 44, 50, 53, 54, 55, 56, 57, 61, 62,
       		               63, 64, 65, 71, 81, 82, 90, 94, 99};
       double vespa_sfh[N_vespa_AgeBins], vespa_metal[N_vespa_AgeBins], dumb[6];
       int ii, jj, kk;
       char buf[1000], sbuf[1000];
       FILE *fa;

       for (ii=1;ii<N_vespa_files;ii++)
        {

       	sprintf(buf, "./devel/vespa_sfh/disc_good_%d.txt", vespa_sfh_IDs[ii]);
       	if(!(fa = fopen(buf, "r")))
       	{
       		char sbuf[1000];
       		sprintf(sbuf, "can't open file `%s'\n", buf);
       		terminate(sbuf);
       	}

       	for(jj=0;jj<6;jj++)
       		fgets(buf, 300, fa);

       	//read vespa SFH and metallicities
       	for (jj=0;jj<N_vespa_AgeBins;jj++)
       	{
       		vespa_sfh[jj]=0.;
       		vespa_metal[jj]=0.;
       		fscanf(fa,"%lg %lg %lg %lg %lg %lg %lg %lg\n", &dumb[0], &dumb[1], &vespa_sfh[jj], &dumb[2], &vespa_metal[jj],
       			                                     &dumb[3], &dumb[4], &dumb[5]);
       	}
       	fclose(fa);

       	for (jj=0;jj<SFH_NBIN;jj++)
       	 {
       		if(jj<N_vespa_AgeBins)
       		{
       			o->sfh_time[jj]=(vespa_age[jj]+vespa_age[jj+1])/2.*1.e9;
       			o->sfh_dt[jj]=(vespa_age[jj+1]-vespa_age[jj])/2.*1.e9;
       		  o->sfh_DiskMass[jj]=vespa_sfh[jj];
       		  o->sfh_BulgeMass[jj]=0.;
       		  o->sfh_MetalsDiskMass[jj]=vespa_metal[jj]*o->sfh_DiskMass[jj];
       		  o->sfh_MetalsBulgeMass[jj]=metals_init();
       		}
       		else
       		{
       			o->sfh_time[jj]=0.;
       			o->sfh_dt[jj]=0.;
       			o->sfh_DiskMass[jj]=0.;
       			o->sfh_BulgeMass[jj]=0.;
       			o->sfh_MetalsDiskMass[jj]=metals_init();
       			o->sfh_MetalsBulgeMass[jj]=metals_init();
       		}
       	 }

        	post_process_spec_mags(o);

        	sprintf(buf, "./devel/vespa_sfh/output_spectradisc_good_%d.txt", vespa_sfh_IDs[ii]);
        	if(!(fa = fopen(buf, "w")))
        	{
        		char sbuf[1000];
        		sprintf(sbuf, "can't open file `%s'\n", buf);
        		terminate(sbuf);
        	}

        	for(jj=0;jj<NMAG;jj++)
        		fprintf(fa,"%e\n",o->Mag[jj]);
        	fclose(fa);

         exit(0);
       }
  */
      //Convert recorded star formation histories into mags
#ifdef NORMALIZEDDB
    post_process_spec_mags(o, &(sfh_bin[0]));
#else
    post_process_spec_mags(o);
#endif

#else //ndef POST_PROCESS_MAGS

#ifdef OUTPUT_REST_MAGS
  // Luminosities are converted into Mags in various bands
  for(j = 0; j < NMAG; j++)
    {
	  //o->Mag[j] = lum_to_mag(g->Lum[j][n]); -> DONE ON TOP FOR LIGHT_OUTPUT AS WELL
	  o->MagBulge[j] = lum_to_mag(g->LumBulge[j][n]);
	  o->MagDust[j] = lum_to_mag(g->LumDust[j][n]);
#ifdef ICL
	  o->MagICL[j] = lum_to_mag(g->ICLLum[j][n]);
#endif
    }
#if defined(READXFRAC) || defined(WITHRADIATIVETRANSFER)
  o->Xfrac3d = g->Xfrac3d;
#endif

#endif //OUTPUT_REST_MAGS
#ifdef OUTPUT_OBS_MAGS
#ifdef COMPUTE_OBS_MAGS
  // Luminosities in various bands
  for(j = 0; j < NMAG; j++)
    {
	  o->ObsMag[j] = lum_to_mag(g->ObsLum[j][n]);
	  o->ObsMagBulge[j] = lum_to_mag(g->ObsLumBulge[j][n]);
	  o->ObsMagDust[j] = lum_to_mag(g->ObsLumDust[j][n]);
#ifdef ICL
	  o->ObsMagICL[j] = lum_to_mag(g->ObsICL[j][n]);
#endif

#ifdef OUTPUT_MOMAF_INPUTS
	  o->dObsMag[j] = lum_to_mag(g->dObsLum[j][n]);
	  o->dObsMagBulge[j] = lum_to_mag(g->dObsLumBulge[j][n]);
	  o->dObsMagDust[j] = lum_to_mag(g->dObsLumDust[j][n]);
#ifdef ICL
	  o->dObsMagICL[j] = lum_to_mag(g->dObsICL[j][n]);
#endif
#endif
    }
#endif //COMPUTE_OBS_MAGS
#endif //OUTPUT_OBS_MAGS
#endif //ndef POST_PROCESS_MAGS
#endif //COMPUTE_SPECPHOT_PROPERTIES

#ifndef NO_PROPS_OUTPUTS
  if((g->DiskMass+g->BulgeMass)> 0.0)
      {
  	  o->MassWeightAge = g->MassWeightAge[n] / (g->DiskMass+g->BulgeMass);
  	  o->MassWeightAge = o->MassWeightAge / 1000. * UnitTime_in_Megayears / Hubble_h;	//Age in Gyr
      }
    else
  	o->MassWeightAge = 0.;
#endif

#ifdef FIX_OUTPUT_UNITS
  fix_units_for_ouput(o);
#endif
#endif //ndef LIGHT_OUTPUT

  // DEBUG
//  printf("  EXIT sfh_bin %d %f\n",sfh_bin,sfh_bin[0].sfh_DiskMass);


}
/* 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 sfh_update_bins(int p, int snap, int step, double time)
{
  /* Adds new bins as required.
   * Then merges bins whenever you have three or more of the same size.
   * Assumes that time counts from zero at the big bang. */
  int i, j; // loop index
  int SFH_ibin; //desired ibin (i.e. bin in question in for loop below)

  SFH_ibin=0;

  Gal[p].sfh_age=time;

  //t=time/SFH_TIME_INTERVAL;
  //ibin=Gal[p].sfh_ibin;
  for(i=0;i<SFH_NBIN;i++)
    if(SFH_Nbins[snap][step][i]>0) //i.e. If bin is active...
      SFH_ibin=i; //Assign with 'bin in question'

  if (Gal[p].sfh_ibin == 0) //i.e. If highest active bin is bin 0...
  {
    for(i=0;i<=SFH_ibin;i++) {
      Gal[p].sfh_t[i]=SFH_t[snap][step][i];
      Gal[p].sfh_Nbins[i]=SFH_Nbins[snap][step][i];
    }
    Gal[p].sfh_ibin=SFH_ibin;
  }
  else //i.e. If highest active bin is > bin 0...
  {
    i=0;
    
    while(i<=SFH_ibin) //Up to 'bin in question'...
    {
      if(i<=Gal[p].sfh_ibin) //...until highest active bin is reached...
      {
	if(Gal[p].sfh_Nbins[i]!= SFH_Nbins[snap][step][i]) //...and until bin has grown to required size.
	{
	  // Merge bins i and i+1
	  Gal[p].sfh_Nbins[i]+=Gal[p].sfh_Nbins[i+1];
	  Gal[p].sfh_t[i]=Gal[p].sfh_t[i+1];
	  Gal[p].sfh_DiskMass[i]+=Gal[p].sfh_DiskMass[i+1];
	  Gal[p].sfh_BulgeMass[i]+=Gal[p].sfh_BulgeMass[i+1];
	  Gal[p].sfh_ICM[i]+=Gal[p].sfh_ICM[i+1];
	  Gal[p].sfh_MetalsDiskMass[i]=metals_add(Gal[p].sfh_MetalsDiskMass[i],Gal[p].sfh_MetalsDiskMass[i+1],1.);
	  Gal[p].sfh_MetalsBulgeMass[i]=metals_add(Gal[p].sfh_MetalsBulgeMass[i],Gal[p].sfh_MetalsBulgeMass[i+1],1.);
	  Gal[p].sfh_MetalsICM[i]= metals_add(Gal[p].sfh_MetalsICM[i],Gal[p].sfh_MetalsICM[i+1],1.);
#ifdef INDIVIDUAL_ELEMENTS
	  Gal[p].sfh_ElementsDiskMass[i] = elements_add(Gal[p].sfh_ElementsDiskMass[i],Gal[p].sfh_ElementsDiskMass[i+1],1.);
	  Gal[p].sfh_ElementsBulgeMass[i] = elements_add(Gal[p].sfh_ElementsBulgeMass[i],Gal[p].sfh_ElementsBulgeMass[i+1],1.);
	  Gal[p].sfh_ElementsICM[i] = elements_add(Gal[p].sfh_ElementsICM[i],Gal[p].sfh_ElementsICM[i+1],1.);
#endif
#ifdef TRACK_BURST
	  Gal[p].sfh_BurstMass[i]+=Gal[p].sfh_BurstMass[i+1];
#endif
	  // Relabel all the other bins
	  for(j=i+1;j<Gal[p].sfh_ibin;j++) {
	    Gal[p].sfh_Nbins[j]=Gal[p].sfh_Nbins[j+1];
	    Gal[p].sfh_t[j]=Gal[p].sfh_t[j+1];
	    Gal[p].sfh_DiskMass[j]=Gal[p].sfh_DiskMass[j+1];
	    Gal[p].sfh_BulgeMass[j]=Gal[p].sfh_BulgeMass[j+1];
	    Gal[p].sfh_ICM[j]=Gal[p].sfh_ICM[j+1];
	    Gal[p].sfh_MetalsDiskMass[j]=Gal[p].sfh_MetalsDiskMass[j+1];
	    Gal[p].sfh_MetalsBulgeMass[j]=Gal[p].sfh_MetalsBulgeMass[j+1];
	    Gal[p].sfh_MetalsICM[j]=Gal[p].sfh_MetalsICM[j+1];
#ifdef INDIVIDUAL_ELEMENTS
	    Gal[p].sfh_ElementsDiskMass[j]=Gal[p].sfh_ElementsDiskMass[j+1];
	    Gal[p].sfh_ElementsBulgeMass[j]=Gal[p].sfh_ElementsBulgeMass[j+1];
	    Gal[p].sfh_ElementsICM[j]=Gal[p].sfh_ElementsICM[j+1];
#endif
#ifdef TRACK_BURST
	    Gal[p].sfh_BurstMass[j]=Gal[p].sfh_BurstMass[j+1];
#endif
	  }

	  //set last bin to zero
	  Gal[p].sfh_flag[j]=0;
	  Gal[p].sfh_Nbins[j]=0;
	  Gal[p].sfh_t[j]=0.;
	  Gal[p].sfh_DiskMass[j]=0.;
	  Gal[p].sfh_BulgeMass[j]=0.;
	  Gal[p].sfh_ICM[j]=0.;
	  Gal[p].sfh_MetalsDiskMass[j]=metals_init();
	  Gal[p].sfh_MetalsBulgeMass[j]=metals_init();
	  Gal[p].sfh_MetalsICM[j]=metals_init();
#ifdef INDIVIDUAL_ELEMENTS
	  Gal[p].sfh_ElementsDiskMass[j]=elements_init();
	  Gal[p].sfh_ElementsBulgeMass[j]=elements_init();
	  Gal[p].sfh_ElementsICM[j]=elements_init();
#endif
#ifdef TRACK_BURST
	  Gal[p].sfh_BurstMass[j]=0.;
#endif
	  Gal[p].sfh_ibin=j-1;
	  
	  /* If there are no more time bins in the galaxy to merge and
	   * the last bin still doesn't have the required size
	   * re-size it according to the reference structure SFH */
	  if(Gal[p].sfh_Nbins[i+1]==0) {
	    Gal[p].sfh_Nbins[i]=SFH_Nbins[snap][step][i];
	    Gal[p].sfh_t[i]=SFH_t[snap][step][i];
	    i+=1;
	  }
	}
	else
	  i+=1;
      }
      else {
	//no more bins available in the galaxy, fill the rest times from SFH array
	for(j=i;j<=SFH_ibin;j++) {
	  Gal[p].sfh_Nbins[j]=SFH_Nbins[snap][step][j];
	  Gal[p].sfh_t[j]=SFH_t[snap][step][j];
	  Gal[p].sfh_DiskMass[j]=0.;
	  Gal[p].sfh_BulgeMass[j]=0.;
	  Gal[p].sfh_ICM[j]=0.;
	  Gal[p].sfh_MetalsDiskMass[j]=metals_init();
	  Gal[p].sfh_MetalsBulgeMass[j]=metals_init();
	  Gal[p].sfh_MetalsICM[j]=metals_init();
#ifdef INDIVIDUAL_ELEMENTS
	  Gal[p].sfh_ElementsDiskMass[j]=elements_init();
	  Gal[p].sfh_ElementsBulgeMass[j]=elements_init();
	  Gal[p].sfh_ElementsICM[j]=elements_init();
#endif
#ifdef TRACK_BURST
	  Gal[p].sfh_BurstMass[j]=0.;
#endif
	  Gal[p].sfh_ibin=j;
	}
	i=j;
      }
    }//end while
  }//end else

  for(i=0;i<SFH_NBIN;i++) {
    if(i==0)
      Gal[p].sfh_dt[i]=NumToTime(0)-Gal[p].sfh_t[i];
    else
      Gal[p].sfh_dt[i]=Gal[p].sfh_t[i-1]-Gal[p].sfh_t[i];
  }
}
void create_sfh_bins()
{
  double previoustime, newtime, deltaT, time;
  int snap, step, sfh_ibin, i, j, sfh_Nbins[SFH_NBIN];
  int ibin_max=0;
  double sfh_t[SFH_NBIN];

  for(snap = 0; snap < MAXSNAPS; snap++) {
      for(step=0;step < STEPS;step++) {
	  for(j=0;j < SFH_NBIN;j++) {
	      SFH_t[snap][step][j]=0;
	      SFH_dt[snap][step][j]=0;
	      SFH_ibin[snap][step]=0;
	      SFH_Nbins[snap][step][j] = 0;
	  }
      }
  }

  for(i=0;i<SFH_NBIN;i++) {
    sfh_Nbins[i]=0;
    sfh_t[i]=0.;
  }
  sfh_ibin=0;

	//for(snap=0;snap<(LastDarkMatterSnapShot+1)-1;snap++) {
  for(snap=0;snap<(LastDarkMatterSnapShot+1);snap++) {
    previoustime = NumToTime(snap);
    newtime = NumToTime(snap+1);
    deltaT = previoustime - newtime;

    for(step=0;step<STEPS;step++) {
      int ibin;
      int flag_merged_bins; // Boolean used to check whether have merged bins
      int dt_merge; // Size of bins that we are checking for merging
      int n_merge; // Number of bins of this size

      time = previoustime - (step + 1.0) * (deltaT / STEPS);
      ibin=sfh_ibin;

      //printf("sna=%d step=%d step time=%f time low=%f\n",
      //		snap,step,(previoustime - (step + 0.5) * (deltaT / STEPS))*UnitTime_in_years/Hubble_h/1.e9,
      //		(time)*UnitTime_in_years/Hubble_h/1.e9);
      //Add one extra bin
      if(snap==0 && step==0) {
      	sfh_t[0]=time;
      	sfh_Nbins[0]=1;
      }
      else {
      	ibin+=1;
      	if(ibin==SFH_NBIN)
      		terminate("sfh_update_bins: too many bins required\n");
      	ibin_max=max(ibin_max,ibin);
      	sfh_Nbins[ibin]=1;
      	sfh_t[ibin]=time;
      }

      /* Now merge bins where we have SFH_NMERGE bins of the same size.
       * Need to do this iteratively. */
      flag_merged_bins=1;
      while(flag_merged_bins)
	{
	  flag_merged_bins=0;
	  dt_merge=sfh_Nbins[0];
	  i=0;
	  // Will have checked all bins once dt_merge drops to zero
	  while(!flag_merged_bins && dt_merge>0)
	    {
	      // Count number of bins of this size
	      n_merge=0;
	      // The i=i below is to suppress a warning message
	      for(i=i;sfh_Nbins[i]==dt_merge;i++) n_merge+=1;
	      /* If fewer than SFH_NMERGE bins then do nothing
	       * (SFH_NMERGE+1 bins if dt_merge=1)
	       * else exit loop and flag for merging */
	      if (n_merge<SFH_NMERGE || (n_merge==SFH_NMERGE && dt_merge==1))
		{
		  /* In new version of the code, treat smallest bins just like any others */
		  //if (n_merge<SFH_NMERGE) {
		  dt_merge/=2;
		  n_merge=0;
		}
	      else {
		  flag_merged_bins=1;
		  i=i-n_merge;
      		}
	    }
	
	  /* At this point, if flag_merged_bins is set then
	   * we have to merge SFH_NMERGE bins into SFH_NMERGE-1. */
	  if(flag_merged_bins) {
	      /* Merge bins i and i+1 */
	      sfh_Nbins[i]*=2;
	      sfh_t[i]=sfh_t[i+1];
	      /* Relabel all the other bins */
	      for(i=i+1;i<ibin;i++) {
		  sfh_Nbins[i]=sfh_Nbins[i+1];
		  sfh_t[i]=sfh_t[i+1];
	      }
	      sfh_Nbins[i]=0;
	      sfh_t[i]=0.;
	      ibin=i-1;
	  }
	} // End loop over bin merging

      sfh_ibin=ibin;

      //if(step==19)
      //printf("snap=%d\n",snap+1);
      for(j=0;j<=sfh_ibin;j++)
      {
      	SFH_t[snap][step][j]=sfh_t[j]; //Time to present at the low-z edge of the bin (code units)
      	SFH_Nbins[snap][step][j]=sfh_Nbins[j];//Number of bins merged in each bin (only useful for the merging algorithm)
      	if(j==0)
      	  SFH_dt[snap][step][j]=NumToTime(0)-sfh_t[j];//Time width of the bin (code units)
      	else
      	  SFH_dt[snap][step][j]=sfh_t[j-1]-sfh_t[j];//Time width of the bin (code units)
      }	
      SFH_ibin[snap][step]=sfh_ibin; //Last active bin

    }//end loop on steps

  }//end loop on snaps

  //exit(0);
#ifdef PARALLEL
  if(ThisTask==0)
#endif
  printf("Max number of SFH bins used = %d\n",ibin_max+1);

}
Ejemplo n.º 7
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");
}
Ejemplo n.º 8
0
 /*@brief Copies all the relevant properties from the Galaxy structure
        into the Galaxy output structure, some units are corrected.*/
void prepare_galaxy_for_output(int n, struct GALAXY *g, struct GALAXY_OUTPUT *o)
{
  int j;

  o->Type = g->Type;
  o->SnapNum = g->SnapNum;
  o->CentralMvir = get_virial_mass(Halo[g->HaloNr].FirstHaloInFOFgroup);
  o->Mvir = g->Mvir;
  o->Rvir = g->Rvir;
  o->Vvir = g->Vvir;

  for(j = 0; j < 3; j++)
    {
	  o->Pos[j] = g->Pos[j];
	  o->DistanceToCentralGal[j] = wrap(Halo[Halo[g->HaloNr].FirstHaloInFOFgroup].Pos[j] - g->Pos[j],BoxSize);;
    }

  o->ColdGas = g->ColdGas;
  o->DiskMass = g->DiskMass;
  o->BulgeMass = g->BulgeMass;
  o->HotGas = g->HotGas;
  o->BlackHoleMass = g->BlackHoleMass;

#ifndef POST_PROCESS_MAGS
#ifdef OUTPUT_REST_MAGS
  /* Luminosities are converted into Mags in various bands */
  for(j = 0; j < NMAG; j++)
 	o->Mag[j] = lum_to_mag(g->Lum[j][n]);
#endif
#endif

#ifndef LIGHT_OUTPUT
  
#ifdef GALAXYTREE
  o->HaloID = HaloIDs[g->HaloNr].HaloID;
  o->Redshift = ZZ[g->SnapNum];

  int ii = (int) floor(o->Pos[0] * ScaleFactor);
  int jj = (int) floor(o->Pos[1] * ScaleFactor);
  int kk = (int) floor(o->Pos[2] * ScaleFactor);

  o->PeanoKey = peano_hilbert_key(ii, jj, kk, Hashbits);

  o->SubID = calc_big_db_subid_index(g->SnapNum, Halo[g->HaloNr].FileNr, Halo[g->HaloNr].SubhaloIndex);

  int tmpfirst = Halo[g->HaloNr].FirstHaloInFOFgroup;
  int lenmax = 0;
  int next = tmpfirst;
  while(next != -1)
    {
      if(Halo[next].Len > lenmax)
	{
	  lenmax = Halo[next].Len;
	  tmpfirst = next;
	}
      next = Halo[next].NextHaloInFOFgroup;
    }

  o->MMSubID = calc_big_db_subid_index(g->SnapNum, Halo[tmpfirst].FileNr, Halo[tmpfirst].SubhaloIndex);
#endif

  o->LookBackTimeToSnap = NumToTime(g->SnapNum)*UnitTime_in_years/Hubble_h;

  o->InfallVmax = g->InfallVmax;
  o->InfallSnap = g->InfallSnap;
  o->HotRadius =  g->HotRadius;
#ifdef HALOPROPERTIES
  o->HaloM_Mean200 = g->HaloM_Mean200;
  o->HaloM_Crit200 = g->HaloM_Crit200;
  o->HaloM_TopHat = g->HaloM_TopHat;
  o->HaloVelDisp = g->HaloVelDisp;
  o->HaloVmax = g->HaloVmax;
#endif

  o->Len = g->Len;
  o->Vmax = g->Vmax;

  o->BulgeSize = g->BulgeSize;
  o->EjectedMass = g->EjectedMass;
  o->BlackHoleGas = g->BlackHoleGas;

  for(j = 0; j < 3; j++)
    {
      o->Vel[j] = g->Vel[j];
#ifdef HALOSPIN
      o->HaloSpin[j] = g->HaloSpin[j];
#endif
      o->GasSpin[j] = g->GasSpin[j];
      o->StellarSpin[j] = g->StellarSpin[j];
#ifdef HALOPROPERTIES
      o->HaloPos[j] = g->HaloPos[j];
      o->HaloVel[j] = g->HaloVel[j];
      o->HaloSpin[j] = g->HaloSpin[j];
#endif      
    }

  o->XrayLum = g->XrayLum;
  o->GasDiskRadius = g->GasDiskRadius;
  o->StellarDiskRadius = g->StellarDiskRadius;
  o->CoolingRadius = g->CoolingRadius;
  o->ICM = g->ICM;
  //o->MetalsICM = CORRECTDBFLOAT(g->MetalsICM);
  o->MetalsICM = g->MetalsICM;
  o->QuasarAccretionRate = g->QuasarAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS;
  o->RadioAccretionRate = g->RadioAccretionRate * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS;
  o->CosInclination = g->CosInclination;

  if(g->Type == 2 || (g->Type == 1 && g->MergeOn == 1)) {
    o->OriMergTime=g->OriMergTime;
    o->MergTime = g->MergTime;
  }
  else {
    o->OriMergTime=0.0;
    o->MergTime = 0.0;
  }


#ifndef GALAXYTREE
  o->HaloIndex = g->HaloNr;
#endif
#ifdef MBPID
  o->MostBoundID = g->MostBoundID;
#endif


#ifdef GALAXYTREE
  o->DisruptOn = g->DisruptOn;
#endif
#ifdef MERGE01
  o->MergeOn = g->MergeOn;
#endif


//METALS

  /*o->MetalsColdGas = CORRECTDBFLOAT(g->MetalsColdGas);
  o->MetalsDiskMass = CORRECTDBFLOAT(g->MetalsDiskMass);
  o->MetalsBulgeMass = CORRECTDBFLOAT(g->MetalsBulgeMass);
  o->MetalsHotGas = CORRECTDBFLOAT(g->MetalsHotGas);
  o->MetalsEjectedMass = CORRECTDBFLOAT(g->MetalsEjectedMass);   
#ifdef METALS_SELF
  o->MetalsHotGasSelf = CORRECTDBFLOAT(g->MetalsHotGasSelf);
#endif*/
  o->MetalsColdGas = g->MetalsColdGas;
  o->MetalsDiskMass = g->MetalsDiskMass;
  o->MetalsBulgeMass = g->MetalsBulgeMass;
  o->MetalsHotGas = g->MetalsHotGas;
  o->MetalsEjectedMass = g->MetalsEjectedMass;
#ifdef METALS_SELF
  o->MetalsHotGasSelf = g->MetalsHotGasSelf;
#endif



 //STAR FORMATION HISTORIES / RATES

#ifdef STAR_FORMATION_HISTORY
  o->sfh_ibin=g->sfh_ibin;
  for (j=0;j<=o->sfh_ibin;j++) {
  	// Lookback time from output snap to middle of SFh bin, in years
 	  o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.-NumToTime(g->SnapNum))*UnitTime_in_years/Hubble_h;
 	  //o->sfh_time[j]=(g->sfh_t[j]+g->sfh_dt[j]/2.)*UnitTime_in_years/Hubble_h; //ROB: Lookback time to middle of SFH bin, in years
 	  o->sfh_dt[j]=g->sfh_dt[j]*UnitTime_in_years/Hubble_h;
 	  o->sfh_DiskMass[j]=g->sfh_DiskMass[j];
 	  o->sfh_BulgeMass[j]=g->sfh_BulgeMass[j];
 	  o->sfh_ICM[j]=g->sfh_ICM[j];
 	  o->sfh_MetalsDiskMass[j]=g->sfh_MetalsDiskMass[j];
 	  o->sfh_MetalsBulgeMass[j]=g->sfh_MetalsBulgeMass[j];
 	  o->sfh_MetalsICM[j]=g->sfh_MetalsICM[j];
#ifdef YIELDS
	  o->sfh_ElementsDiskMass[j]=g->sfh_ElementsDiskMass[j];
	  o->sfh_ElementsBulgeMass[j]=g->sfh_ElementsBulgeMass[j];
	  o->sfh_ElementsICM[j]=g->sfh_ElementsICM[j];
#endif
   }

  for (j=o->sfh_ibin+1;j<SFH_NBIN;j++) {
	  o->sfh_time[j]=0.;
	  o->sfh_DiskMass[j]=0.;
	  o->sfh_BulgeMass[j]=0.;
	  o->sfh_ICM[j]=0.;
	  o->sfh_MetalsDiskMass[j]=metals_init();
	  o->sfh_MetalsBulgeMass[j]=metals_init();
	  o->sfh_MetalsICM[j]=metals_init();
#ifdef YIELDS
	  o->sfh_ElementsDiskMass[j]=elements_init();
	  o->sfh_ElementsBulgeMass[j]=elements_init();
	  o->sfh_ElementsICM[j]=elements_init();
#endif
  }
#endif

#ifdef YIELDS
  /*for (j=0;j<ELEMENT_NUM;j++)
  {
	  o->DiskMass_elements[j]=g->DiskMass_elements[j];
	  o->BulgeMass_elements[j]=g->BulgeMass_elements[j];
	  o->ColdGas_elements[j]=g->ColdGas_elements[j];
	  o->HotGas_elements[j]=g->HotGas_elements[j];
	  o->EjectedMass_elements[j]=g->EjectedMass_elements[j];
	  o->ICM_elements[j]=g->ICM_elements[j];
  }*/

  /*o->DiskMass_elements = CORRECTDBFLOAT(g->DiskMass_elements);
  o->BulgeMass_elements = CORRECTDBFLOAT(g->BulgeMass_elements);
  o->ColdGas_elements = CORRECTDBFLOAT(g->ColdGas_elements);
  o->HotGas_elements = CORRECTDBFLOAT(g->HotGas_elements);
  o->ICM_elements = CORRECTDBFLOAT(g->ICM_elements);*/
  o->DiskMass_elements = g->DiskMass_elements;
  o->BulgeMass_elements = g->BulgeMass_elements;
  o->ColdGas_elements = g->ColdGas_elements;
  o->HotGas_elements = g->HotGas_elements;
  o->EjectedMass_elements = g->EjectedMass_elements;
  o->ICM_elements = g->ICM_elements;
#endif

 //NOTE: in Msun/yr
#ifdef SAVE_MEMORY
  o->Sfr = CORRECTDBFLOAT(g->Sfr * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
#else
  o->Sfr = CORRECTDBFLOAT(g->Sfr[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
  o->SfrBulge = CORRECTDBFLOAT(g->SfrBulge[n] * UnitMass_in_g / UnitTime_in_s * SEC_PER_YEAR / SOLAR_MASS);
#endif 




//MAGNITUDES

#ifdef POST_PROCESS_MAGS
    //Convert recorded star formation histories into mags
    post_process_mags(o);
#else //POST_PROCESS_MAGS

#ifdef OUTPUT_REST_MAGS
  // Luminosities are converted into Mags in various bands
  for(j = 0; j < NMAG; j++)
    {
	  //o->Mag[j] = lum_to_mag(g->Lum[j][n]); -> DONE ON TOP FOR LIGHT_OUTPUT AS WELL
	  o->MagBulge[j] = lum_to_mag(g->LumBulge[j][n]);
	  o->MagDust[j] = lum_to_mag(g->LumDust[j][n]);
#ifdef ICL
	  o->MagICL[j] = lum_to_mag(g->ICLLum[j][n]);
#endif
    }

 
  if((g->DiskMass+g->BulgeMass)> 0.0)
    {
	  o->MassWeightAge = g->MassWeightAge[n] / (g->DiskMass+g->BulgeMass);
	  o->MassWeightAge = o->MassWeightAge / 1000. * UnitTime_in_Megayears / Hubble_h;	//Age in Gyr
    }
  else
	o->MassWeightAge = 0.;

#endif //OUTPUT_REST_MAGS
#ifdef OUTPUT_OBS_MAGS
#ifdef COMPUTE_OBS_MAGS
  // Luminosities in various bands
  for(j = 0; j < NMAG; j++)
    {
	  o->ObsMag[j] = lum_to_mag(g->ObsLum[j][n]);
	  o->ObsMagBulge[j] = lum_to_mag(g->ObsLumBulge[j][n]);
	  o->ObsMagDust[j] = lum_to_mag(g->ObsLumDust[j][n]);
#ifdef ICL
	  o->ObsMagICL[j] = lum_to_mag(g->ObsICL[j][n]);
#endif

#ifdef OUTPUT_MOMAF_INPUTS
	  o->dObsMag[j] = lum_to_mag(g->dObsLum[j][n]);
	  o->dObsMagBulge[j] = lum_to_mag(g->dObsLumBulge[j][n]);
	  o->dObsMagDust[j] = lum_to_mag(g->dObsLumDust[j][n]);
#endif
    }
#endif //COMPUTE_OBS_MAGS
#endif //OUTPUT_OBS_MAGS
#endif //POST_PROCESS_MAGS

#ifdef FIX_OUTPUT_UNITS
  fix_units_for_ouput(o);
#endif
#endif //ndef LIGHT_OUTPUT
}