Files @ b7792cb187f7
Branch filter:

Location: MD/arcos/src/photo.c

greta
Edited file README via RhodeCode
/** @file photo.c
 *  @brief Routines for the calculation of the photoionization source term.
 *
 * We use the Helmholtz approximation for the kernel in the photoionization
 * integral and we use the routines of the Poisson solver for the Helmholtz
 * equation (FISHPACK was modified to take a new inhomogeneous term into
 * account).
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "cdr.h"
#include "interpol2.h"
#include "mapper.h"
#include "parameters.h"
#include "photo.h"
#include "poisson.h"
#include "proto.h"
#include "rz_array.h"
#include "species.h"

void photo_copy (mapper_t *mapper, grid_t *source, grid_t *target, 
		 int ir, int iz, int itheta);
void photo_coarsen (mapper_t *mapper, grid_t *source, grid_t *target, 
		    int ir, int iz, int itheta);
int photo_interpol_set (mapper_t *mapper, grid_t *source, 
			 interpol_t *interpol,
			 int pr, int pz, int itheta);
void photo_interpol (mapper_t *mapper, grid_t *source, grid_t *target, 
		     interpol_t *interpol, 
		     int ir, int iz, int itheta);

photo_term_t *photo_terms = NULL;

mapper_t photo_mapper = {&interpol_bilin, photo_coarsen, photo_copy,
			 photo_interpol_set, photo_interpol};

mapper_t *photo_mappers[] = {&photo_mapper, NULL};

pois_problem_t *pois_photo_1;
pois_problem_t *pois_photo_2;
extern pois_problem_t *pois_electrostatic;

/** @brief Initializes photoionization QQQQ? */
void
photo_init ()
{
  /* Since it makes no sense, we use photo_extra_levels < 0 to say that
     the conditions for the photoionization are the same as for
     the electrostatic problem.  This is needed for backwards compatibility. */
  if (extra_photo_levels < 0) 
  {
    pois_photo_1 = pois_electrostatic;
    pois_photo_2 = pois_electrostatic;
    return;
  }

  /* Two different sets of refinement criteria for the two photoionization
     terms. If extra_photo_levels_2 < 0, then pois_photo_2 = pois_photo_1 */
  pois_photo_1 = xmalloc (sizeof (pois_problem_t));

  pois_photo_1->max_level = photo_max_level;
  pois_photo_1->extra_levels = extra_photo_levels;
  pois_photo_1->max_error = photo_max_error;

  pois_photo_1->bnd_right = photo_bnd_right;
  pois_photo_1->bnd_top = photo_bnd_top;
  pois_photo_1->bnd_bottom = photo_bnd_bottom;

  if (extra_photo_levels_2 < 0)
  {
     pois_photo_2 = pois_photo_1;
     return;
  }

  pois_photo_2 = xmalloc (sizeof (pois_problem_t));

  pois_photo_2->max_level = photo_max_level_2;
  pois_photo_2->extra_levels = extra_photo_levels_2;
  pois_photo_2->max_error = photo_max_error_2;

  pois_photo_2->bnd_right = photo_bnd_right_2;
  pois_photo_2->bnd_top = photo_bnd_top_2;
  pois_photo_2->bnd_bottom = photo_bnd_bottom_2;
}


/** @brief Copies the photoionization QQQQ? */
void
photo_copy (mapper_t *mapper, grid_t *source, grid_t *target, 
	    int ir, int iz, int itheta)
{
  cdr_grid_t *cdr;
  pois_grid_t *pois;

  cdr = (cdr_grid_t*) target;
  pois = (pois_grid_t*) source;

  RZT (cdr->photo, ir, iz, itheta) = RZ (pois->phi, ir, iz);
}

/** @brief Coarsens the photoionization QQQQ? */
void 
photo_coarsen (mapper_t *mapper, grid_t *source, grid_t *target, 
	       int ir, int iz, int itheta)
{
  cdr_grid_t *cdr;
  pois_grid_t *pois;
  int level_diff, z, r;

  cdr = (cdr_grid_t*) target;
  pois = (pois_grid_t*) source;

  level_diff = pois->level - cdr->level;

  z = (iz << level_diff) + (1 << (level_diff - 1));
  r = (ir << level_diff) + (1 << (level_diff - 1));

  if (grid_contains (source, r, z, GRID_INSIDE) && 
      grid_contains (source, r - 1, z, GRID_INSIDE) &&
      grid_contains (source, r, z - 1, GRID_INSIDE) &&
      grid_contains (source, r - 1, z - 1, GRID_INSIDE)) {
    
    RZT (cdr->photo, ir, iz, itheta)  = 0.25 *
      (RZ (pois->phi, r, z) 
       + RZ (pois->phi, r - 1, z) 
       + RZ (pois->phi, r, z - 1) 
       + RZ (pois->phi, r - 1, z - 1));
  }

}

/** @brief photo_interpol_set QQQQ? */
int 
photo_interpol_set (mapper_t *mapper, grid_t *source, interpol_t *interpol,
		      int pr, int pz, int itheta)
{
  pois_grid_t *pois;

  pois = (pois_grid_t*) source;

  interpol_set_stencil (interpol,
			r_at (pr, pois->level),
			z_at (pz, pois->level),
			RZ (pois->phi, pr, pz), 
			RZ (pois->phi, pr, pz + 1),
			RZ (pois->phi, pr + 1, pz), 
			RZ (pois->phi, pr + 1, pz + 1));

  return TRUE;
}

/** @brief photo_interpol QQQQ? */
void
photo_interpol (mapper_t *mapper, grid_t *source, grid_t *target, 
		interpol_t *interpol, int ir, int iz, int itheta)
{
  double r, z;
  cdr_grid_t *cdr;

  cdr = (cdr_grid_t *) target;

  r = r_at (ir, cdr->level);
  z = z_at (iz, cdr->level);

  RZT (cdr->photo, ir, iz, itheta) = interpol_apply (interpol, r, z);
}


/** @brief Registers a photoionization term with given @a A and @a lambda. */
void
photo_register (double A, double lambda)
{
  photo_term_t *t;

  t = (photo_term_t *) xmalloc (sizeof (photo_term_t));

  t->A = A;
  t->lambda = lambda;
  t->next = photo_terms;

  photo_terms = t;
}

/** @brief Copies a list of photo terms into @a *dest. */
void
photo_copy_list (photo_term_t *src, photo_term_t **dest)
{
  photo_term_t *ptr_term;
  photo_term_t *p = NULL, *p1;

  *dest = NULL;

  while (src) {
    p1 = (photo_term_t *) xmalloc (sizeof (photo_term_t));
    if (p) {
      p->next = p1;
    } else {
      *dest = p1;
    }

    p = p1;
    p->A = src->A;
    p->lambda = src->lambda;
    src = src->next;
  }

  if (p) p->next = NULL;
}


/** @brief Unregisters all the photoionization terms and
 *  frees the allocated space.
 */
void
photo_unregister_all (void)
{
  photo_term_t *t, *next;

  for (t = photo_terms; t; t = next) {
    next = t->next;
    free (t);
  }

  photo_terms = NULL;
}

/** @brief Transforms back the photoionization calculation into real space. */
void
photo_dft_r (cdr_grid_t *grid, int sign)
{
  cdr_grid_t *leaf;

  debug (3, "photo_dft_r(" grid_printf_str ", %d)\n", 
	 grid_printf_args(grid), sign);

  iter_childs (grid, leaf) {
    photo_dft_r (leaf, sign);
  }

  dft_transform (grid->photo, grid->photo, sign);
}

/** @brief Copies the derivative of the ion density into cdr->charge
 *
 * The ion density, which is supposed to be at this point, the impact
 * ionization) into cdr->charge, which will be used as the source for
 * the Poisson/Helmholtz solver. */
void
photo_copy_source (cdr_grid_t *grid)
{
  int ir, iz, itheta;

   debug(3, "photo_copy_source (" grid_printf_str ")\n",
	 grid_printf_args(grid));

#pragma omp parallel
  {
#pragma omp for private (ir, iz)
    iter_grid_3d_n (grid, ir, iz, itheta, 2) {
      RZT (grid->charge, ir, iz, itheta) = 
	RZT (grid->d_dens[ions], ir, iz, itheta) / grid->ntheta;
    }
  }
}

/** @brief Recursive version of @a photo_copy_source. */
mk_recursive (photo_copy_source, cdr_grid_t)

/** @brief Once a photoionization term is computed, we add it to d_dens.
 *
 * Note that we already copied the contents of d_dens[ions] into
 * charge, so when we solve again the Helholtz equation, the source
 * is still the same.
 */
void
photo_add_term (photo_term_t *term, cdr_grid_t *cdr)
{
  int s, ir, iz, itheta;
  int updated[2] = {electrons, photo_ions};
  
  debug (3, "photo_add_term (" photo_printf_str ", " grid_printf_str ")\n",
	 photo_printf_args(term), grid_printf_args(cdr));
    
#pragma omp parallel
    {
#pragma omp for private (ir, iz, s)
      iter_grid_3d_n (cdr, ir, iz, itheta, 2) {
	for (s = 0; s < 2; s++) {
	  RZT (cdr->d_dens[updated[s]], ir, iz, itheta) += 
	    term->A * RZT (cdr->photo, ir, iz, itheta);
	}
      }
    }  
}

/** @brief ...and the recursive version of @a photo_add_term */
void
photo_add_term_r (photo_term_t *term, cdr_grid_t *cdr)
{
  cdr_grid_t *child;

  photo_add_term (term, cdr);

  iter_childs (cdr, child) {
    photo_add_term_r (term, child);
  }
}

/** @brief photo_calc_term QQQQ */
pois_grid_t **
photo_calc_term (photo_term_t *term, cdr_grid_t *cdr, int i)
{
  /* Call to the generic Poisson/Helmholtz solver */
  if (i == 1) {
	return pois_gen_solve_a (cdr, pois_photo_2, photo_mappers, term->lambda);
  } else {
	return pois_gen_solve_a (cdr, pois_photo_1, photo_mappers, term->lambda);
  }
}

/** @brief Calculates the photoionization and adds it to the derivatives
 *  of the species densities. */
void
photo_calc (photo_term_t *terms, cdr_grid_t *cdr)
{
  pois_grid_t **pois_modes;
  photo_term_t *term;
  // photo_term_t *ptr_term;

  photo_copy_source_r (cdr);
  
  if (cdr->ntheta != 1)
    cdr_dft_charge_r (cdr, 1);
  
  // for (ptr_term = terms; ptr_term != NULL; ptr_term = ptr_term->next) {
  //   printf("terms: A=%g lambda=%g ptr=%d\n", ptr_term->A, ptr_term->lambda, (int)ptr_term->next);
  // }

  int j = 0;
  for (term = terms; term; term = term->next ) {
    int i;
    pois_modes = photo_calc_term (term, cdr, j);
    j++;
    if (cdr->ntheta != 1)
      photo_dft_r (cdr, -1);

    photo_add_term_r (term, cdr);
    debug (3, "photo_calc (" photo_printf_str ", " grid_printf_str ")\n",
        	 photo_printf_args(term), grid_printf_args(cdr));

    /* Free the allocated memory. */
    for (i = 0; i < max_ntheta; i++) {      
      pois_free_r (pois_modes[i]);
    }
    free (pois_modes);
  }
}

/** @brief Loads a photoionization file, consisting in a series of rows with
   @a A and @a lambda. */
void
photo_load_file (char *fname)
{
  FILE *fp;
  double A, lambda;
  int c;
  int i;

  printf("\n");
  printf ("Loading photoionization data from `%s'...\n", fname);
  printf("\n");
  fp = fopen (fname, "r");

  if (NULL == fp) {
    warning ("Unable to open photoionization file `%s'\n", fname);
    exit (-1);
    return;
  }

  
  i=0;
  do {
    c = fscanf (fp, "%lf %lf", &A, &lambda);
    if (c != 2) {
      break;
    }

    printf ("Registring photoionization term A = %.5g, lambda = %.4g\n",
	    A, lambda);

    photo_register (A, lambda);
    i++;
  } while (TRUE);
  printf("\n");

  fclose (fp);
}