|
new file 100644
|
|
|
/** @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);
|
|
|
}
|