Example #1
0
void lineofsight_output(void)
{
  char buf[500];
  int n, s, next;
  double ti;

  next = find_next_lineofsighttime(All.Ti_nextlineofsight);

  ti = All.TimeBegin * exp(next * All.Timebase_interval);

  if(ThisTask == 0)
    {
      printf("Line of sight output! ThisTask=%d Time=%g  NextTime=%g\n", ThisTask, All.Time, ti);
      fflush(stdout);
    }

  H_a = hubble_function(All.Time);
  Wmax = All.Time * H_a * All.BoxSize;


  if(ThisTask == 0)
    {
      sprintf(buf, "%s/los", All.OutputDir);
      mkdir(buf, 02755);
    }

  Los = mymalloc(sizeof(struct line_of_sight));
  LosGlobal = mymalloc(sizeof(struct line_of_sight));

  for(n = 0, s = 0; n < N_LOS; n++)
    {
      if(s + 3 >= RNDTABLE)
	{
	  set_random_numbers();
	  s = 0;
	}

      Los->zaxis = (int) (3.0 * get_random_number(s++));
      switch (Los->zaxis)
	{
	case 2:
	  Los->xaxis = 0;
	  Los->yaxis = 1;
	  break;
	case 0:
	  Los->xaxis = 1;
	  Los->yaxis = 2;
	  break;
	case 1:
	  Los->xaxis = 2;
	  Los->yaxis = 0;
	  break;
	}

      Los->Xpos = All.BoxSize * get_random_number(s++);
      Los->Ypos = All.BoxSize * get_random_number(s++);

#ifdef OUTPUTLINEOFSIGHT_SPECTRUM
      add_along_lines_of_sight();
      sum_over_processors_and_normalize();
      absorb_along_lines_of_sight();
      output_lines_of_sight(n);
#endif

#ifdef OUTPUTLINEOFSIGHT_PARTICLES
      find_particles_and_save_them(n);
#endif
    }

  myfree(LosGlobal);
  myfree(Los);
}
Example #2
0
void radtransfer_update_chemistry(void)
{
  int i, j;
  double nH, temp, molecular_weight;
  double nHII;
  double dt, dtime, a3inv, c_light;
  double A, B, CC;
  double x;
  double n_gamma;
  double alpha_HII, gamma_HI; 
  double total_nHI, total_V, total_nHI_all, total_V_all;

#ifdef RT_INCLUDE_HE
  double nHe, alpha_HeII, alpha_HeIII, gamma_HeI, gamma_HeII;
  double nHe, nHeII, nHeIII;
  double y, D, E, F, G, J;
  double total_nHeI, total_nHeI_all;

  total_nHeI = 0;
#endif
      
  total_nHI = total_V = 0;

  dt = (All.Radiation_Ti_endstep - All.Radiation_Ti_begstep) * All.Timebase_interval;
  
  if(All.ComovingIntegrationOn)
    {
      dtime = dt / hubble_function(All.Time);
      a3inv = 1.0 / All.Time / All.Time / All.Time;
    }
  else
    {
      dtime = dt;
      a3inv = 1.0;
    }

  c_light = C / All.UnitVelocity_in_cm_per_s;

  for(i = 0; i < N_gas; i++)
    if(P[i].Type == 0)
      {
	nH = (HYDROGEN_MASSFRAC * SphP[i].d.Density * a3inv) / (PROTONMASS / All.UnitMass_in_g * All.HubbleParam);
	
	molecular_weight = 4 / (1 + 3 * HYDROGEN_MASSFRAC + 4 * HYDROGEN_MASSFRAC * SphP[i].n_elec);
	
	temp = (SphP[i].Entropy + SphP[i].e.DtEntropy * dt) * pow(SphP[i].d.Density * a3inv, GAMMA_MINUS1) *
	  (molecular_weight * PROTONMASS / All.UnitMass_in_g * All.HubbleParam) /
	  (BOLTZMANN / All.UnitEnergy_in_cgs * All.HubbleParam);

	/* collisional ionization rate */
	gamma_HI = 5.85e-11 * pow(temp, 0.5) * exp(-157809.1 / temp) / (1.0 + pow(temp / 1e5, 0.5));
	gamma_HI *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	gamma_HI *= All.HubbleParam * All.HubbleParam;
	
	/* alpha_B recombination coefficient */
	alpha_HII = 2.59e-13 * pow(temp / 1e4, -0.7);
	alpha_HII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	alpha_HII *= All.HubbleParam * All.HubbleParam;
	
#ifdef RT_INCLUDE_HE
	nHe = ((1.0 - HYDROGEN_MASSFRAC) * SphP[i].d.Density * a3inv) / (4.0 * PROTONMASS / All.UnitMass_in_g * All.HubbleParam);   

	/* collisional ionization rate */
	gamma_HeI = 2.38e-11 * pow(temp, 0.5) * exp(-285335.4 / temp) / (1.0 + pow(temp / 1e5, 0.5));
	gamma_HeI *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	gamma_HeI *= All.HubbleParam * All.HubbleParam;
	
	gamma_HeII = 5.68e-12 * pow(temp, 0.5) * exp(-631515 / temp) / (1.0 + pow(temp / 1e5, 0.5));
	gamma_HeII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	gamma_HeII *= All.HubbleParam * All.HubbleParam;
	
	/* alpha_B recombination coefficient */
	alpha_HeII = 1.5e-10 * pow(temp, -0.6353);
	alpha_HeII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	alpha_HeII *= All.HubbleParam * All.HubbleParam;
	
	alpha_HeIII = 3.36e-10 * pow(temp, -0.5) * pow(temp / 1e3, -0.2) / (1.0 + pow(temp / 1e6, 0.7));
	alpha_HeIII *= All.UnitTime_in_s / All.UnitLength_in_cm / All.UnitLength_in_cm / All.UnitLength_in_cm;
	alpha_HeIII *= All.HubbleParam * All.HubbleParam;
#endif
	
	for(j = 0; j < N_BINS; j++)
	  {
#ifdef RT_INCLUDE_HE
	    x = SphP[i].nHI * nH * rt_sigma_HI[j] / 
	      (SphP[i].nHI * nH * rt_sigma_HI[j] + SphP[i].nHeI * nHe * rt_sigma_HeI[j] + SphP[i].nHeII * nHe * rt_sigma_HeII[j]);
#else
	    x = 1.0;
#endif

	    n_gamma = SphP[i].n_gamma[j] / P[i].Mass * a3inv;

	    /* number of photons should be positive */
	    if(n_gamma < 0 || isnan(n_gamma))
	      {
		printf("NEGATIVE n_gamma: %g %d %d \n", n_gamma, i, ThisTask);
		printf("n_gamma[j] %g mass %g a3inv %g \n", SphP[i].n_gamma[j], P[i].Mass, a3inv);
		endrun(111);
	      }

	    A = dtime * gamma_HI * nH;
	    B = dtime * c_light * rt_sigma_HI[j] * x;
	    CC = dtime * alpha_HII* nH;
	    
	    /* semi-implicit scheme for ionization */
	    nHII =  (SphP[i].nHII + B * n_gamma + A * SphP[i].n_elec) /
	      (1.0 + B * n_gamma + CC * SphP[i].n_elec + A * SphP[i].n_elec);

	    if(nHII < 0 || nHII > 1 || isnan(nHII))
	      {
		printf("ERROR nHII %g \n", nHII);
		endrun(333);
	      }
	    
	    SphP[i].n_elec = nHII;
	    
	    SphP[i].nHII = nHII;
	    
	    SphP[i].nHI = 1.0 - nHII;
	    

#ifdef RT_INCLUDE_HE
	    SphP[i].n_elec += SphP[i].nHeII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC);
	    SphP[i].n_elec += 2.0 * SphP[i].nHeIII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC);

	    y = SphP[i].nHeI * nHe * rt_sigma_HeI[j] / 
	      (SphP[i].nHI * nH * rt_sigma_HI[j] + SphP[i].nHeI * nHe * rt_sigma_HeI[j] + SphP[i].nHeII * nHe * rt_sigma_HeII[j]);
	    
	    D = dtime * gamma_HeII * nH;
	    E = dtime * alpha_HeIII * nH;
	    F = dtime * gamma_HeI * nH;
	    G = dtime * c_light * rt_sigma_HeI[j] * y;
	    J = dtime * alpha_HeII * nH;
	    
	    nHeII =
	      SphP[i].nHeII + F * SphP[i].n_elec + G * n_gamma -
	      ((F * SphP[i].n_elec + G * n_gamma - E * SphP[i].n_elec) / (1.0 +
									     E * SphP[i].n_elec) *
	       SphP[i].nHeIII);
	    
	    nHeII /= 1.0 + F * SphP[i].n_elec + G * n_gamma + D * SphP[i].n_elec + J * SphP[i].n_elec +
	      ((F * SphP[i].n_elec + G * n_gamma - E * SphP[i].n_elec) / (1.0 +
									     E * SphP[i].n_elec) * D *
	       SphP[i].n_elec);
	    
	    if(nHeII < 0 || nHeII > 1 || isnan(nHeII))
	      {
		printf("ERROR neHII %g\n", nHeII);
		endrun(333);
	      }
	    
	    nHeIII = (SphP[i].nHeIII + D * nHeII * SphP[i].n_elec) / (1.0 + E * SphP[i].n_elec);
	    
	    if(nHeIII < 0 || nHeIII > 1)
	      {
		printf("ERROR nHeIII %g\n", nHeIII);
		endrun(222);
	      }
	    
	    SphP[i].n_elec = SphP[i].nHII;
	    SphP[i].n_elec += nHeII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC);
	    SphP[i].n_elec += 2.0 * nHeIII * (1.0 - HYDROGEN_MASSFRAC) / (4.0 * HYDROGEN_MASSFRAC);
	    
	    SphP[i].nHeII = nHeII;
	    SphP[i].nHeIII = nHeIII;
	    
	    SphP[i].nHeI = 1.0 - SphP[i].nHeII - SphP[i].nHeIII;
	    
	    if(SphP[i].nHeI < 0 || SphP[i].nHeI > 1 || isnan(SphP[i].nHeI))
	      {
		printf("ERROR nHeI %g\n", SphP[i].nHeI);
		endrun(444);
	      }
#endif
	  }	    


#ifdef RT_INCLUDE_HE
	total_nHeI += SphP[i].nHeI * P[i].Mass / (SphP[i].d.Density * a3inv);
#endif
	total_nHI += SphP[i].nHI * P[i].Mass / (SphP[i].d.Density * a3inv);
	total_V += P[i].Mass / (SphP[i].d.Density * a3inv);
	
      }
  
  MPI_Allreduce(&total_nHI, &total_nHI_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
  MPI_Allreduce(&total_V, &total_V_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

#ifdef RT_INCLUDE_HE
  MPI_Allreduce(&total_nHeI, &total_nHeI_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#endif  

  /* output the input of photon density in physical units */
  if(ThisTask == 0)
    {
      fprintf(FdRad, "%g %g ", All.Time, total_nHI_all / total_V_all);
#ifdef RT_INCLUDE_HE
      fprintf(FdRad, "%g\n", total_nHeI_all / total_V_all);
#else
      fprintf(FdRad, "\n");
#endif
      fflush(FdRad);
    }
}
Example #3
0
void subfind_determine_sub_halo_properties(struct unbind_data *d, int num, double *totmass,
					   double *pos, double *vel, double *cm, double *veldisp,
					   double *vmax, double *vmaxrad, double *spin,
					   MyIDType * mostboundid, double *halfmassrad, double *mass_tab)
{
  int i, j, p;
  double s[3], v[3], max, vel_to_phys, H_of_a, atime, minpot;
  double lx, ly, lz, dv[3], dx[3], disp;
  double boxhalf, boxsize, ddxx;
  sort_r2list *rr_list = 0;
  int minindex;
  double mass, maxrad;


  boxsize = All.BoxSize;
  boxhalf = 0.5 * boxsize;
 
  if(All.ComovingIntegrationOn)
    {
      vel_to_phys = 1.0 / All.Time;
      H_of_a = hubble_function(All.Time);
      atime = All.Time;
    }
  else
    {
      vel_to_phys = atime = 1;
      H_of_a = 0;
    }

  for(i = 0, minindex = -1, minpot = 1.0e30; i < num; i++)
    {
      p = d[i].index;
      if(P[p].u.DM_Potential < minpot || minindex == -1)
	{
	  minpot = P[p].u.DM_Potential;
	  minindex = p;
	}
    }

  for(j = 0; j < 3; j++)
    pos[j] = P[minindex].Pos[j];


  /* pos[] now holds the position of minimum potential */
  /* we take it that as the center */


  for(i = 0, minindex = -1, minpot = 1.0e30; i < num; i++)
    {
      p = d[i].index;
      if(P[p].v.DM_BindingEnergy < minpot || minindex == -1)
	{
	  minpot = P[p].v.DM_BindingEnergy;
	  minindex = p;
	}
    }

  *mostboundid = P[minindex].ID;


  /* let's get bulk velocity and the center-of-mass */

  for(j = 0; j < 3; j++)
    s[j] = v[j] = 0;

  for(j = 0; j < 6; j++)
    mass_tab[j] = 0;

  for(i = 0, mass = 0; i < num; i++)
    {
      p = d[i].index;
      for(j = 0; j < 3; j++)
	{
#ifdef PERIODIC
	  ddxx = NEAREST(P[p].Pos[j] - pos[j]);
#else
	  ddxx = P[p].Pos[j] - pos[j];
#endif
	  s[j] += P[p].Mass * ddxx;
	  v[j] += P[p].Mass * P[p].Vel[j];
	}
      mass += P[p].Mass;

      mass_tab[P[p].Type] += P[p].Mass;
    }

  *totmass = mass;

  for(j = 0; j < 3; j++)
    {
      s[j] /= mass;		/* center of mass */
      v[j] /= mass;

      vel[j] = vel_to_phys * v[j];
    }

  for(j = 0; j < 3; j++)
    {
      s[j] += pos[j];

#ifdef PERIODIC
      while(s[j] < 0)
	s[j] += boxsize;
      while(s[j] >= boxsize)
	s[j] -= boxsize;
#endif

      cm[j] = s[j];
    }


  disp = lx = ly = lz = 0;

  rr_list = mymalloc(sizeof(sort_r2list) * num);

  for(i = 0; i < num; i++)
    {
      p = d[i].index;
      rr_list[i].r = 0;
      rr_list[i].mass = P[p].Mass;

      for(j = 0; j < 3; j++)
	{
#ifdef PERIODIC
	  ddxx = NEAREST(P[p].Pos[j] - s[j]);
#else
	  ddxx = P[p].Pos[j] - s[j];
#endif
	  dx[j] = atime * ddxx;
	  dv[j] = vel_to_phys * (P[p].Vel[j] - v[j]);
	  dv[j] += H_of_a * dx[j];

	  disp += P[p].Mass * dv[j] * dv[j];
	  /* for rotation curve computation, take minimum of potential as center */
#ifdef PERIODIC
	  ddxx = NEAREST(P[p].Pos[j] - pos[j]);
#else
	  ddxx = P[p].Pos[j] - pos[j];
#endif
	  ddxx = atime * ddxx;
	  rr_list[i].r += ddxx * ddxx;
	}

      lx += P[p].Mass * (dx[1] * dv[2] - dx[2] * dv[1]);
      ly += P[p].Mass * (dx[2] * dv[0] - dx[0] * dv[2]);
      lz += P[p].Mass * (dx[0] * dv[1] - dx[1] * dv[0]);

      rr_list[i].r = sqrt(rr_list[i].r);
    }

  *veldisp = sqrt(disp / (3 * mass));	/* convert to 1d velocity dispersion */

  spin[0] = lx / mass;
  spin[1] = ly / mass;
  spin[2] = lz / mass;


  qsort(rr_list, num, sizeof(sort_r2list), subfind_compare_dist_rotcurve);

  *halfmassrad = rr_list[num / 2].r;

  /* compute cumulative mass */
  for(i = 1; i < num; i++)
    rr_list[i].mass = rr_list[i - 1].mass + rr_list[i].mass;

  for(i = num - 1, max = 0, maxrad = 0; i > 5; i--)
    if(rr_list[i].mass / rr_list[i].r > max)
      {
	max = rr_list[i].mass / rr_list[i].r;
	maxrad = rr_list[i].r;
      }

  *vmax = sqrt(All.G * max);
  *vmaxrad = maxrad;

  myfree(rr_list);
}
Example #4
0
int subfind_unbind(struct unbind_data *ud, int len)
{
  double *bnd_energy, energy_limit, weakly_bound_limit = 0;
  int i, j, p, minindex, unbound, phaseflag;
  double ddxx, s[3], dx[3], v[3], dv[3], pos[3];
  double vel_to_phys, H_of_a, atime, pot, minpot = 0;
  double boxsize, boxhalf;
  double TotMass;

  boxsize = All.BoxSize;
  boxhalf = 0.5 * All.BoxSize;

  if(All.ComovingIntegrationOn)
    {
      vel_to_phys = 1.0 / All.Time;
      H_of_a = hubble_function(All.Time);
      atime = All.Time;
    }
  else
    {
      vel_to_phys = atime = 1;
      H_of_a = 0;
    }

  bnd_energy = (double *) mymalloc(len * sizeof(double));

  phaseflag = 0;		/* this means we will recompute the potential for all particles */

  do
    {
      subfind_loctree_treebuild(len, ud);

      /* let's compute the potential  */

      if(phaseflag == 0)	/* redo it for all the particles */
	{
	  for(i = 0, minindex = -1, minpot = 1.0e30; i < len; i++)
	    {
	      p = ud[i].index;

	      pot = subfind_loctree_treeevaluate_potential(p);
	      /* note: add self-energy */
	      P[p].u.DM_Potential = pot + P[p].Mass / All.SofteningTable[P[p].Type];
	      P[p].u.DM_Potential *= All.G / atime;

	      if(All.TotN_gas > 0 && (FOF_PRIMARY_LINK_TYPES & 1) == 0 && All.OmegaBaryon > 0)
		P[p].u.DM_Potential *= All.Omega0 / (All.Omega0 - All.OmegaBaryon);

	      if(P[p].u.DM_Potential < minpot || minindex == -1)
		{
		  minpot = P[p].u.DM_Potential;
		  minindex = p;
		}
	    }

	  for(j = 0; j < 3; j++)
	    pos[j] = P[minindex].Pos[j];	/* position of minimum potential */
	}
      else
	{
	  /* we only repeat for those close to the unbinding threshold */
	  for(i = 0; i < len; i++)
	    {
	      p = ud[i].index;

	      if(P[p].v.DM_BindingEnergy >= weakly_bound_limit)
		{
		  pot = subfind_loctree_treeevaluate_potential(p);
		  /* note: add self-energy */
		  P[p].u.DM_Potential = pot + P[p].Mass / All.SofteningTable[P[p].Type];
		  P[p].u.DM_Potential *= All.G / atime;

		  if(All.TotN_gas > 0 && (FOF_PRIMARY_LINK_TYPES & 1) == 0 && All.OmegaBaryon > 0)
		    P[p].u.DM_Potential *= All.Omega0 / (All.Omega0 - All.OmegaBaryon);
		}
	    }
	}

      /* let's get bulk velocity and the center-of-mass */

      v[0] = v[1] = v[2] = 0;
      s[0] = s[1] = s[2] = 0;

      for(i = 0, TotMass = 0; i < len; i++)
	{
	  p = ud[i].index;

	  for(j = 0; j < 3; j++)
	    {
#ifdef PERIODIC
	      ddxx = NEAREST(P[p].Pos[j] - pos[j]);
#else
	      ddxx = P[p].Pos[j] - pos[j];
#endif
	      s[j] += P[p].Mass * ddxx;
	      v[j] += P[p].Mass * P[p].Vel[j];
	    }
	  TotMass += P[p].Mass;
	}

      for(j = 0; j < 3; j++)
	{
	  v[j] /= TotMass;
	  s[j] /= TotMass;	/* center-of-mass */

	  s[j] += pos[j];

#ifdef PERIODIC
	  while(s[j] < 0)
	    s[j] += boxsize;
	  while(s[j] >= boxsize)
	    s[j] -= boxsize;
#endif
	}

      for(i = 0; i < len; i++)
	{
	  p = ud[i].index;

	  for(j = 0; j < 3; j++)
	    {
	      dv[j] = vel_to_phys * (P[p].Vel[j] - v[j]);
#ifdef PERIODIC
	      dx[j] = atime * NEAREST(P[p].Pos[j] - s[j]);
#else
	      dx[j] = atime * (P[p].Pos[j] - s[j]);
#endif
	      dv[j] += H_of_a * dx[j];
	    }

	  P[p].v.DM_BindingEnergy =
	    P[p].u.DM_Potential + 0.5 * (dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2]);

#ifdef DENSITY_SPLIT_BY_TYPE
	  if(P[p].Type == 0)
	    P[p].v.DM_BindingEnergy += P[p].w.int_energy;
#endif
	  bnd_energy[i] = P[p].v.DM_BindingEnergy;
	}

      qsort(bnd_energy, len, sizeof(double), subfind_compare_binding_energy);	/* largest comes first! */

      energy_limit = bnd_energy[(int) (0.25 * len)];

      for(i = 0, unbound = 0; i < len - 1; i++)
	{
	  if(bnd_energy[i] > 0)
	    unbound++;
	  else
	    unbound--;

	  if(unbound <= 0)
	    break;
	}
      weakly_bound_limit = bnd_energy[i];

      /* now omit unbound particles,  but at most 1/4 of the original size */

      for(i = 0, unbound = 0; i < len; i++)
	{
	  p = ud[i].index;
	  if(P[p].v.DM_BindingEnergy > 0 && P[p].v.DM_BindingEnergy > energy_limit)
	    {
	      unbound++;
	      ud[i] = ud[len - 1];
	      i--;
	      len--;
	    }
	}

      if(len < All.DesLinkNgb)
	break;

      if(phaseflag == 0)
	{
	  if(unbound > 0)
	    phaseflag = 1;
	}
      else
	{
	  if(unbound == 0)
	    {
	      phaseflag = 0;	/* this will make us repeat everything once more for all particles */
	      unbound = 1;
	    }
	}
    }
  while(unbound > 0);

  myfree(bnd_energy);

  return (len);
}
void cosmic_ray_diffusion(void)
{
  int i, iter;
  double CR_E0_delta0, CR_E0_delta1, CR_E0_alpha, CR_E0_beta;
  double CR_n0_delta0, CR_n0_delta1, CR_n0_alpha, CR_n0_beta;
  double a3inv, dt, rel_change, loc_max_rel_change, glob_max_rel_change;
  double sumnew, sumold, sumtransfer, sumnew_tot, sumold_tot, sumtransfer_tot;
  double kappa, kappa_egy, CR_q_i, cr_efac_i;
  double meanKineticEnergy, qmeanKin;
  int CRpop;

  if(ThisTask == 0)
    {
      printf("Start cosmic ray diffusion...\n");
      fflush(stdout);
    }

  for(CRpop = 0; CRpop < NUMCRPOP; CRpop++)
    {
      CR_E0[CRpop] = (double *) mymalloc("CR_E0[CRpop]", N_gas * sizeof(double));
      CR_E0_Old[CRpop] = (double *) mymalloc("CR_E0_Old[CRpop]", N_gas * sizeof(double));
      CR_E0_Kappa[CRpop] = (double *) mymalloc("CR_E0_Kappa[CRpop]", N_gas * sizeof(double));
    }

  CR_E0_Residual = (double *) mymalloc("CR_E0_Residual", N_gas * sizeof(double));
  CR_E0_DVec = (double *) mymalloc("CR_E0_DVec", N_gas * sizeof(double));
  CR_E0_QVec = (double *) mymalloc("CR_E0_QVec", N_gas * sizeof(double));

  for(CRpop = 0; CRpop < NUMCRPOP; CRpop++)
    {
      CR_n0[CRpop] = (double *) mymalloc("CR_n0[CRpop]", N_gas * sizeof(double));
      CR_n0_Old[CRpop] = (double *) mymalloc("CR_n0_Old[CRpop]", N_gas * sizeof(double));
      CR_n0_Kappa[CRpop] = (double *) mymalloc("CR_n0_Kappa[CRpop]", N_gas * sizeof(double));
    }

  CR_n0_Residual = (double *) mymalloc("CR_n0_Residual", N_gas * sizeof(double));
  CR_n0_DVec = (double *) mymalloc("CR_n0_DVec", N_gas * sizeof(double));
  CR_n0_QVec = (double *) mymalloc("CR_n0_QVec", N_gas * sizeof(double));

  if(All.ComovingIntegrationOn)
    a3inv = 1 / (All.Time * All.Time * All.Time);
  else
    a3inv = 1.0;


  dt = (All.CR_Diffusion_Ti_endstep - All.CR_Diffusion_Ti_begstep) * All.Timebase_interval;

  if(All.ComovingIntegrationOn)
    dt *= All.Time / hubble_function(All.Time);

  if(ThisTask == 0)
    {
      printf("dt=%g\n", dt);
    }

  /* First, let's compute the diffusivities for each particle */

  for(i = 0; i < N_gas; i++)
    {
      if(P[i].Type == 0)
	{
	  for(CRpop = 0; CRpop < NUMCRPOP; CRpop++)
	    {
	      CR_E0[CRpop][i] = CR_E0_Old[CRpop][i] = SphP[i].CR_E0[CRpop];
	      CR_n0[CRpop][i] = CR_n0_Old[CRpop][i] = SphP[i].CR_n0[CRpop];

	      kappa = All.CR_DiffusionCoeff;

	      if(All.CR_DiffusionDensScaling != 0.0)
		kappa *=
		  pow(SphP[i].d.Density * a3inv / All.CR_DiffusionDensZero, All.CR_DiffusionDensScaling);

	      if(All.CR_DiffusionEntropyScaling != 0.0)
		kappa *= pow(SphP[i].Entropy / All.CR_DiffusionEntropyZero, All.CR_DiffusionEntropyScaling);

	      if(SphP[i].CR_E0[CRpop] > 0)
		{
		  CR_q_i = SphP[i].CR_q0[CRpop] * pow(SphP[i].d.Density * a3inv, 0.33333);

		  cr_efac_i =
		    CR_Tab_MeanEnergy(CR_q_i, All.CR_Alpha[CRpop] - 0.3333) /
		    CR_Tab_MeanEnergy(CR_q_i, All.CR_Alpha[CRpop]);

		  kappa *= (All.CR_Alpha[CRpop] - 1) / (All.CR_Alpha[CRpop] - 1.33333) * pow(CR_q_i, 0.3333);

		  kappa_egy = kappa * cr_efac_i;
		}
	      else
		kappa_egy = kappa;

	      CR_E0_Kappa[CRpop][i] = kappa_egy;
	      CR_n0_Kappa[CRpop][i] = kappa;

	      /* we'll factor the timestep into the diffusivities, for simplicity */
	      CR_E0_Kappa[CRpop][i] *= dt;
	      CR_n0_Kappa[CRpop][i] *= dt;
	    }
	}
    }



  /* Let's start the Conjugate Gradient Algorithm */

  /* Initialization */
  for(CRpop = 0; CRpop < NUMCRPOP; CRpop++)
    {
      cosmic_ray_diffusion_matrix_multiply(CR_E0_Old[CRpop], CR_E0_Residual, CR_n0_Old[CRpop], CR_n0_Residual,
					   CRpop);

      for(i = 0; i < N_gas; i++)
	{
	  if(P[i].Type == 0)
	    {
	      CR_E0_Residual[i] = CR_E0_Old[CRpop][i] - CR_E0_Residual[i];
	      CR_E0_DVec[i] = CR_E0_Residual[i];

	      CR_n0_Residual[i] = CR_n0_Old[CRpop][i] - CR_n0_Residual[i];
	      CR_n0_DVec[i] = CR_n0_Residual[i];
	    }
	}

      CR_E0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_E0_Residual, CR_E0_Residual);
      CR_E0_delta0 = CR_E0_delta1;

      CR_n0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_n0_Residual, CR_n0_Residual);
      CR_n0_delta0 = CR_n0_delta1;

      iter = 0;			/* iteration counter */
      glob_max_rel_change = 1 + CR_DIFFUSION_ITER_ACCURACY;	/* to make sure that we enter the iteration */


      while(iter < MAX_CR_DIFFUSION_ITER && glob_max_rel_change > CR_DIFFUSION_ITER_ACCURACY
	    && CR_E0_delta1 > 0)
	{
	  cosmic_ray_diffusion_matrix_multiply(CR_E0_DVec, CR_E0_QVec, CR_n0_DVec, CR_n0_QVec, CRpop);

	  CR_E0_alpha = CR_E0_delta1 / cosmic_ray_diffusion_vector_multiply(CR_E0_DVec, CR_E0_QVec);
	  CR_n0_alpha = CR_n0_delta1 / cosmic_ray_diffusion_vector_multiply(CR_n0_DVec, CR_n0_QVec);

	  for(i = 0, loc_max_rel_change = 0; i < N_gas; i++)
	    {
	      CR_E0[CRpop][i] += CR_E0_alpha * CR_E0_DVec[i];
	      CR_E0_Residual[i] -= CR_E0_alpha * CR_E0_QVec[i];
	      CR_n0[CRpop][i] += CR_n0_alpha * CR_n0_DVec[i];
	      CR_n0_Residual[i] -= CR_n0_alpha * CR_n0_QVec[i];

	      if(CR_E0[CRpop][i] > 0)
		{
		  rel_change = CR_E0_alpha * CR_E0_DVec[i] / CR_E0[CRpop][i];
		  if(loc_max_rel_change < rel_change)
		    loc_max_rel_change = rel_change;
		}
	      if(CR_n0[CRpop][i] > 0)
		{
		  rel_change = CR_n0_alpha * CR_n0_DVec[i] / CR_n0[CRpop][i];
		  if(loc_max_rel_change < rel_change)
		    loc_max_rel_change = rel_change;
		}
	    }

	  CR_E0_delta0 = CR_E0_delta1;
	  CR_E0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_E0_Residual, CR_E0_Residual);
	  CR_n0_delta0 = CR_n0_delta1;
	  CR_n0_delta1 = cosmic_ray_diffusion_vector_multiply(CR_n0_Residual, CR_n0_Residual);

	  CR_E0_beta = CR_E0_delta1 / CR_E0_delta0;
	  CR_n0_beta = CR_n0_delta1 / CR_n0_delta0;

	  for(i = 0; i < N_gas; i++)
	    {
	      CR_E0_DVec[i] = CR_E0_Residual[i] + CR_E0_beta * CR_E0_DVec[i];
	      CR_n0_DVec[i] = CR_n0_Residual[i] + CR_n0_beta * CR_n0_DVec[i];
	    }

	  iter++;

	  MPI_Allreduce(&loc_max_rel_change, &glob_max_rel_change, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);

	  if(ThisTask == 0)
	    {
	      printf
		("cosmic ray diffusion iter=%d  CR_E0_delta1=%g delta1/delta0=%g CR_n0_delta1=%g delta1/delta0=%g  max-rel-change=%g\n",
		 iter, CR_E0_delta1, CR_E0_delta1 / CR_E0_delta0, CR_n0_delta1, CR_n0_delta1 / CR_n0_delta0,
		 glob_max_rel_change);
	      fflush(stdout);
	    }
	}



      /* Now we have the solution vectors */
      /* set the new cosmic ray prorperties */


      for(i = 0, sumnew = sumold = sumtransfer = 0; i < N_gas; i++)
	{
	  if(P[i].Type == 0)
	    {
	      SphP[i].CR_E0[CRpop] = CR_E0[CRpop][i];
	      SphP[i].CR_n0[CRpop] = CR_n0[CRpop][i];
	      SphP[i].CR_DeltaE[CRpop] = 0;
	      SphP[i].CR_DeltaN[CRpop] = 0;

	      if(SphP[i].CR_n0[CRpop] > 1.0e-12 && SphP[i].CR_E0[CRpop] > 0)
		{
		  meanKineticEnergy = SphP[i].CR_E0[CRpop] * m_p / SphP[i].CR_n0[CRpop];

		  qmeanKin = CR_q_from_mean_kinetic_energy(meanKineticEnergy, CRpop);

		  SphP[i].CR_q0[CRpop] = qmeanKin * pow(SphP[i].d.Density * a3inv, -(1.0 / 3.0));
		  SphP[i].CR_C0[CRpop] = SphP[i].CR_n0[CRpop] * (All.CR_Alpha[CRpop] - 1.0)
		    * pow(SphP[i].CR_q0[CRpop], All.CR_Alpha[CRpop] - 1.0);
		}
	      else
		{
		  SphP[i].CR_E0[CRpop] = 0.0;
		  SphP[i].CR_n0[CRpop] = 0.0;

		  SphP[i].CR_q0[CRpop] = 1.0e10;
		  SphP[i].CR_C0[CRpop] = 0.0;
		}

	      sumnew += CR_E0[CRpop][i];
	      sumold += CR_E0_Old[CRpop][i];
	      sumtransfer += fabs(CR_E0[CRpop][i] - CR_E0_Old[CRpop][i]);
	    }
	}

      MPI_Allreduce(&sumnew, &sumnew_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
      MPI_Allreduce(&sumold, &sumold_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
      MPI_Allreduce(&sumtransfer, &sumtransfer_tot, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

      if(ThisTask == 0)
	{
	  printf
	    ("\ncosmic ray diffusion finished. energy_before=%g energy_after=%g  rel-change=%g rel-transfer=%g\n\n",
	     sumold_tot, sumnew_tot, sumold_tot ? ((sumnew_tot - sumold_tot) / sumold_tot) : 0.0,
	     sumold_tot ? (sumtransfer_tot / sumold_tot) : 0.0);
	  fflush(stdout);
	}
    }

  myfree(CR_E0_QVec);
  myfree(CR_E0_DVec);
  myfree(CR_E0_Residual);

  myfree(CR_n0_QVec);
  myfree(CR_n0_DVec);
  myfree(CR_n0_Residual);

  for(CRpop = 0; CRpop < NUMCRPOP; CRpop++)
    {
      myfree(CR_n0_Kappa[CRpop]);
      myfree(CR_n0_Old[CRpop]);
      myfree(CR_n0[CRpop]);

      myfree(CR_E0_Kappa[CRpop]);
      myfree(CR_E0_Old[CRpop]);
      myfree(CR_E0[CRpop]);
    }
}
Example #6
0
void radtransfer(void)
{
  int i, j, iter;
  double alpha_cg, beta, delta_old, delta_new, sum, old_sum, min_diag, glob_min_diag, max_diag, glob_max_diag;
  double timestep, nH, je=0;
  double rel, res, maxrel, glob_maxrel;
  double DQ;

  NextActiveParticleRT = (int *) mymalloc(N_gas * sizeof(int));
  XVec = (double *) mymalloc(N_gas * sizeof(double));
  QVec = (double *) mymalloc(N_gas * sizeof(double));
  DVec = (double *) mymalloc(N_gas * sizeof(double));
  Residue = (double *) mymalloc(N_gas * sizeof(double));
  Kappa = (double *) mymalloc(N_gas * sizeof(double));
  Lambda = (double *) mymalloc(N_gas * sizeof(double));
  Diag = (double *) mymalloc(N_gas * sizeof(double));
  Zvec = (double *) mymalloc(N_gas * sizeof(double));
  Diag2 = (double *) mymalloc(N_gas * sizeof(double));

  c_light = C / All.UnitVelocity_in_cm_per_s;
  sigma = 6.3e-18 / All.UnitLength_in_cm / All.UnitLength_in_cm * All.HubbleParam * All.HubbleParam;;


  /*  the actual time-step we need to do */
  timestep = (All.Radiation_Ti_endstep - All.Radiation_Ti_begstep) * All.Timebase_interval;

  if(All.ComovingIntegrationOn)
    {
      a3inv = 1 / (All.Time * All.Time * All.Time);
      hubble_a = hubble_function(All.Time);
      /* in comoving case, timestep is dloga at this point. Convert to dt */
      timestep /= hubble_a;
    }
  else
    {
      a3inv = hubble_a = 1.0;
    }

  //radtransfer_get_active();

  dt = timestep / NSTEP;
  
  for(i = 0; i < NSTEP; i++)
    {
      if(ThisTask == 0)
	{
	  printf("%s %i\n", "the step is ", i);
	  printf("%s %g\n", "c_light is ", c_light);
	  printf("%s %g\n", "dt is ", dt);
	  fflush(stdout);
	}
      
      /* initialization for the CG method */
      
      for(j = 0; j < N_gas; j++)
	if(P[j].Type == 0)
#ifdef RT_VAR_DT
	  if(SphP[j].rt_flag == 1)
#endif
	    {
	      XVec[j] = SphP[j].n_gamma;
	      
	      nH = (SphP[j].d.Density * a3inv) / (PROTONMASS / All.UnitMass_in_g * All.HubbleParam); //physical
	      
	      Kappa[j] = (SphP[j].nHI + 1.0e-8) * nH * sigma; //physical
	      
	      /* physical kappa = 1/distance => comoving is 1/(distance/a) = a/distance = a * kappa */
	      if(All.ComovingIntegrationOn)
		Kappa[j] = (Kappa[j] + 3.0 * hubble_a / c_light) * All.Time; //comoving
	      
#ifdef RADTRANSFER_FLUXLIMITER
	      /* now calculate flux limiter */
	      
	      if(SphP[j].n_gamma > 0)
		{
		  double R =  sqrt(SphP[j].Grad_ngamma[0] * SphP[j].Grad_ngamma[0] +
				   SphP[j].Grad_ngamma[1] * SphP[j].Grad_ngamma[1] +
				   SphP[j].Grad_ngamma[2] * SphP[j].Grad_ngamma[2]) / (SphP[j].n_gamma * Kappa[j]);
		  
		  if(All.ComovingIntegrationOn)
		    R /= All.Time;
		  
		  Lambda[j] = (1+R)/(1+R+R*R);
		  if(Lambda[j] <  1e-100)
		    Lambda[j] = 0;
		}
	      else
		Lambda[j] = 1.0;
#endif 	    
	    }
      
      /* add the source term */
      
      for(j = 0; j < N_gas; j++)
	if(P[j].Type == 0)
#ifdef RT_VAR_DT
	  if(SphP[j].rt_flag == 1)
#endif
	    {
	      SphP[j].n_gamma += dt * SphP[j].Je * P[j].Mass;
	      if(SphP[j].Je)
		je+=SphP[j].Je;
	  }
      // printf("glowing particles lum %g \n", je);
      
      radtransfer_matrix_multiply(XVec, Residue, Diag);
      
      for(j = 0; j < N_gas; j++)
	if(P[j].Type == 0)
#ifdef RT_VAR_DT
	  if(SphP[j].rt_flag == 1)
#endif
	    Residue[j] = SphP[j].n_gamma - Residue[j];
      
      /* Let's take the diagonal matrix elements as Jacobi preconditioner */
      
      for(j = 0, min_diag = MAX_REAL_NUMBER, max_diag = -MAX_REAL_NUMBER; j < N_gas; j++)
	if(P[j].Type == 0)
#ifdef RT_VAR_DT
	  if(SphP[j].rt_flag == 1)
#endif
	    {
	      /* note: in principle we would have to substract the w_ii term, but this is always zero */
	      
	      if(Diag[j] < min_diag)
		min_diag = Diag[j];
	      if(Diag[j] > max_diag)
		max_diag = Diag[j];
	      
	      Zvec[j] = Residue[j] / Diag[j];
	      DVec[j] = Zvec[j];
	    }
      
      MPI_Allreduce(&min_diag, &glob_min_diag, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
      MPI_Allreduce(&max_diag, &glob_max_diag, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
      
      delta_new = radtransfer_vector_multiply(Zvec, Residue);
      delta_old = delta_new;
	
      old_sum = radtransfer_vector_sum(XVec);
      
      if(ThisTask == 0)
	printf("\nBegin CG iteration\nold |x|=%g, min-diagonal=%g, max-diagonal=%g\n", old_sum,
	       glob_min_diag, glob_max_diag);
      
      
      /* begin the CG method iteration */
      iter = 0;
      
      do
	{
	  radtransfer_matrix_multiply(DVec, QVec, Diag2);
	  
	  DQ = radtransfer_vector_multiply(DVec, QVec);
	  if(DQ == 0)
	    alpha_cg = 0;
	  else
	    alpha_cg = delta_new / DQ;
	  
	  
	  for(j = 0, maxrel = 0; j < N_gas; j++)
	    {
	      XVec[j] += alpha_cg * DVec[j];
	      Residue[j] -= alpha_cg * QVec[j];
	      
	      Zvec[j] = Residue[j] / Diag[j];
	      
	      rel = fabs(alpha_cg * DVec[j]) / (XVec[j] + 1.0e-10);
	      if(rel > maxrel)
		maxrel = rel;
	    }
	  
	  delta_old = delta_new;
	  delta_new = radtransfer_vector_multiply(Zvec, Residue);
	  
	  sum = radtransfer_vector_sum(XVec);
	  res = radtransfer_vector_sum(Residue);
	  
	  if(delta_old)
	    beta = delta_new / delta_old;
	  else
	    beta = 0;
	  
	  for(j = 0; j < N_gas; j++)
	    DVec[j] = Zvec[j] + beta * DVec[j];
	  
	  MPI_Allreduce(&maxrel, &glob_maxrel, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
	  
	  if(ThisTask == 0)
	    {
	      printf("radtransfer: iter=%3d  |res|/|x|=%12.6g  maxrel=%12.6g  |x|=%12.6g | res|=%12.6g\n",
		     iter, res/sum, glob_maxrel, sum, res);
	      fflush(stdout);
	    }
	  
	  iter++;
	}
      while((res > ACCURACY * sum && glob_maxrel > ACCURACY  && iter < MAX_ITER) || iter < 2);
      
      if(ThisTask == 0)
	printf("\n");
      
      /* update the intensity */
      for(j = 0; j < N_gas; j++)
	if(P[j].Type == 0)
#ifdef RT_VAR_DT
	  if(SphP[j].rt_flag == 1)
#endif
	    {
	      if(XVec[j] < 0 && XVec[j] > -EPSILON)
		XVec[j] = 0;
	      
	      SphP[j].n_gamma = XVec[j];
	    }
      
      /* update the chemistry */
      radtransfer_update_chemistry();
    }
  
  myfree(Diag2);
  myfree(Zvec);
  myfree(Diag);
  myfree(Lambda);
  myfree(Kappa);
  myfree(Residue);
  myfree(DVec);
  myfree(QVec);
  myfree(XVec);
  myfree(NextActiveParticleRT);

}