|
new file 100644
|
|
|
/** @file reaction.c
|
|
|
* @brief Functions to handle the "reaction" part of
|
|
|
* convection-diffusion-reaction equation.
|
|
|
*/
|
|
|
#include <stdlib.h>
|
|
|
#include <stdio.h>
|
|
|
#include <math.h>
|
|
|
|
|
|
#include "cdr.h"
|
|
|
#include "grid.h"
|
|
|
#include "parameters.h"
|
|
|
#include "photo.h"
|
|
|
#include "proto.h"
|
|
|
#include "react_table.h"
|
|
|
#include "species.h"
|
|
|
#include "reaction.h"
|
|
|
|
|
|
static void fill_react_gaps ();
|
|
|
|
|
|
reaction_t *reactions_list = NULL;
|
|
|
extern double z_cutoff;
|
|
|
double species_written[20];
|
|
|
|
|
|
/** @brief Returns the position in the species-array of a given species.
|
|
|
*
|
|
|
* Returns -1 if not found. */
|
|
|
int
|
|
|
find_species_by_name(const char *spec_name)
|
|
|
{
|
|
|
int res = -1;
|
|
|
int cnt;
|
|
|
|
|
|
for (cnt = 0; cnt < no_species; cnt++)
|
|
|
{
|
|
|
if (strcmp(spec_index[cnt]->name, spec_name) == 0)
|
|
|
res = cnt;
|
|
|
}
|
|
|
|
|
|
if (res == -1) {
|
|
|
printf("Species-lookup-failure: %s!\n",spec_name);
|
|
|
assert(1 == 0);
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
/** @brief Adds a given reaction to the reaction list */
|
|
|
void
|
|
|
react_add (reaction_t *react)
|
|
|
{
|
|
|
react_table *rt;
|
|
|
|
|
|
debug (3, "react_add (...)\n");
|
|
|
|
|
|
printf("Adding reaction with table: %s\n",react->tablefile);
|
|
|
|
|
|
rt = (react_table *) xmalloc (sizeof(react_table));
|
|
|
|
|
|
if (react->tablefile != NULL) {
|
|
|
react_table_read(react->tablefile, rt);
|
|
|
react->rt = rt;
|
|
|
}
|
|
|
|
|
|
react->next = reactions_list;
|
|
|
reactions_list = react;
|
|
|
}
|
|
|
|
|
|
/** @brief Applies a reaction to the given @a grid */
|
|
|
void
|
|
|
react_apply (reaction_t *react, cdr_grid_t *grid, int overwrite)
|
|
|
{
|
|
|
int i, ir, iz, itheta;
|
|
|
rz_array_t *grid_in[REACTION_MAX_IN], *grid_out[REACTION_MAX_IN + REACTION_MAX_OUT],
|
|
|
*grid_eabs;
|
|
|
double *in = NULL, *out = NULL, eabs;
|
|
|
double test;
|
|
|
double rate;
|
|
|
int pos;
|
|
|
double e1, e2, val1, val2, log_e, res, r_mod;
|
|
|
int cnt, curr_species;
|
|
|
|
|
|
debug (3, "react_apply (..., " grid_printf_str ")\n",
|
|
|
grid_printf_args (grid));
|
|
|
|
|
|
grid_eabs = grid->dens[no_species];
|
|
|
|
|
|
for (i = 0; i < react->nin; i++) {
|
|
|
grid_in[i] = grid->dens[react->input[i]];
|
|
|
grid_out[i] = grid->d_dens[react->input[i]];
|
|
|
}
|
|
|
|
|
|
for (i = react->nin; i < react->nin + react->nout; i++) {
|
|
|
grid_out[i] = grid->d_dens[react->output[i - react->nin]];
|
|
|
}
|
|
|
|
|
|
#pragma omp parallel private(ir, iz, i, in, out)
|
|
|
{
|
|
|
/* malloc(0) is legal, but I do not want to play with fire. */
|
|
|
if (react->nin > 0) {
|
|
|
in = (double *) xmalloc (sizeof(double) * react->nin);
|
|
|
}
|
|
|
|
|
|
/* Do not know what use nout == 0 may have, (perhaps some debugging?)
|
|
|
but we leave it here as theoretically possible. */
|
|
|
if (react->nout > 0) {
|
|
|
out = (double *) xmalloc (sizeof(double) * (react->nout + react->nin));
|
|
|
}
|
|
|
|
|
|
|
|
|
#pragma omp for
|
|
|
iter_grid_theta(grid, itheta) { //ITER3
|
|
|
iter_grid_z(grid, iz) { //ITER2
|
|
|
double back_dens;
|
|
|
if (sprite_module) {
|
|
|
back_dens = spr_density_at (z_at (iz, grid->level));
|
|
|
} else {
|
|
|
back_dens = 1.0;
|
|
|
}
|
|
|
|
|
|
|
|
|
iter_grid_r(grid, ir) { //ITER1
|
|
|
if ( z_at (iz, grid->level) < z_cutoff ) { //IF1
|
|
|
eabs = fabs (RZT(grid_eabs, ir, iz, itheta));
|
|
|
for (i = 0; i < react->nin; i++) {
|
|
|
in[i] = fabs (RZT(grid_in[i], ir, iz, itheta));
|
|
|
}
|
|
|
|
|
|
log_e = log10(eabs);
|
|
|
|
|
|
/* If the supplied fieldstrength falls outside the boundaries of the table,
|
|
|
return predetermined under-/overflow values */
|
|
|
if (log_e < react->rt->e_min) {
|
|
|
rate = react->rt->underflow;
|
|
|
} else if (log_e > react->rt->e_min + react->rt->e_step * react->rt->steps) {
|
|
|
rate = react->rt->overflow;
|
|
|
} else {
|
|
|
pos = floor((log_e - react->rt->e_min) / react->rt->e_step);
|
|
|
val1 = react->rt->values[pos];
|
|
|
val2 = react->rt->values[pos+1];
|
|
|
e1 = pow(10, react->rt->e_min + react->rt->e_step * (double) pos);
|
|
|
e2 = e1 * pow(10, react->rt->e_step);
|
|
|
|
|
|
rate = val1 + ((val2 - val1) / (e2 - e1)) * (eabs - e1);
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < react->nin; i++){ rate *= MYMAX(0, in[i]); }
|
|
|
|
|
|
for (i = 0; i < react->nin + react->nout; i++) { //FOR1
|
|
|
if (i < react->nin) {
|
|
|
curr_species = react->input[i]; r_mod = -rate;
|
|
|
} else { curr_species = react->output[i - react->nin]; r_mod = rate; }
|
|
|
|
|
|
if (spec_index[curr_species]->charge != 0.0) {
|
|
|
RZT(grid_out[i], ir, iz, itheta) += r_mod;
|
|
|
}
|
|
|
} //FOR1
|
|
|
} //IF1
|
|
|
} //ITER1
|
|
|
} //ITER2
|
|
|
} //ITER3
|
|
|
free (in);
|
|
|
free (out);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** @brief Recursive version of @a react_apply */
|
|
|
void
|
|
|
react_apply_r (reaction_t *react, cdr_grid_t *grid, int overwrite)
|
|
|
{
|
|
|
cdr_grid_t *child;
|
|
|
|
|
|
react_apply (react, grid, overwrite);
|
|
|
|
|
|
iter_childs (grid, child) {
|
|
|
react_apply_r (react, child, overwrite);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** @brief Sets the d_dens field of a grid to zero */
|
|
|
void
|
|
|
zero_fill (cdr_grid_t* grid)
|
|
|
{
|
|
|
int ir, iz, itheta, i;
|
|
|
|
|
|
iter_grid_3d (grid, ir, iz, itheta)
|
|
|
for (i = 0; i < no_species; i++) {
|
|
|
RZT(grid->d_dens[i], ir, iz, itheta) = 0.0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** @brief Applies all reactions to the given @a grid and his descendants */
|
|
|
void
|
|
|
react_apply_all (cdr_grid_t *grid)
|
|
|
{
|
|
|
reaction_t *react;
|
|
|
int overwrite;
|
|
|
int last = -1;
|
|
|
int cnt;
|
|
|
|
|
|
zero_fill(grid);
|
|
|
|
|
|
overwrite = TRUE;
|
|
|
|
|
|
for (react = reactions_list; react; react = react->next) {
|
|
|
if (react->is_photo) {
|
|
|
photo_calc (photo_terms, grid);
|
|
|
} else {
|
|
|
react_apply_r (react, grid, overwrite);
|
|
|
}
|
|
|
overwrite = FALSE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** @brief Fill in the gaps that we left in the definitions */
|
|
|
static void
|
|
|
fill_react_gaps ()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
/** @brief Initializes the list of reactions. */
|
|
|
void
|
|
|
react_init ()
|
|
|
{
|
|
|
/* Note that the reactions are applied in inverse order than listed here. */
|
|
|
/* Rest of the kinetic model: */
|
|
|
kinetic_init ();
|
|
|
|
|
|
}
|
|
|
|
|
|
/** Below this electric field, we do not waste time calculating anything.
|
|
|
Besides, this avoid NaNs for eabs == 0. */
|
|
|
#define EPS_EABS 1e-6
|