⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 convconv.c

📁 卷积程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************
 *	Specify photon beam profile, and convolute over the beam.
 *
 ****/

#include "conv.h"

/****************************************************************
 *	If IBMPC is 1, file extensions are limited to 3 letters
 *	at most.
 ****/
#define IBMPC 0

/****************************************************************
 *	Used by convolution over Gaussian beam.  Ignore the value
 *	beyond GAUSSLIMIT radius.
 ****/
#define GAUSSLIMIT 4


/***********************Declarations****************************/
FILE       *GetWriteFile(char *);
void        AllocConvData(InputStruct *, OutStruct *);
void        FreeConvData(InputStruct *, OutStruct *);
float       qtrap(float (*) (float), float, float, float);
double      BessI0(double);

/****************************************************************
 *	Data structures for the binary tree used to store part of
 *	the integrand evaluation.
 ****/
struct Node {
  float       x, y;
  struct Node *left, *right;
};

typedef struct Node *LINK;
typedef LINK TREE;

/****************************************************************
 *	A global structure to pass the current coordinate of the
 * 	physical quantities being evaluated and the pointers of the
 *	input and output parameters to the integration function.
 ****/
struct {
  double      r;
  short       iz, ia;
  InputStruct *in_ptr;
  OutStruct  *out_ptr;
  TREE        tree;		/* A tree to store ITheta() &*
				 * ExpBessI0(). */
}           ConvVar;


/***********************Convolution*****************************/
/****************************************************************
 *	Specify the parameters for a flat beam.
 ****/
void
GetFlatBeam(BeamStruct * Beam_Ptr)
{
  Beam_Ptr->type = flat;

  printf("Total energy of the flat beam [J]: ");
  Beam_Ptr->P = GetFloat(FLT_MIN, FLT_MAX);
  printf("Radius of the flat beam [cm]: ");
  Beam_Ptr->R = GetFloat(FLT_MIN, FLT_MAX);
  printf("Total power: %8.2lg J, and radius: %8.2lg cm.\n",
	 Beam_Ptr->P, Beam_Ptr->R);
}

/****************************************************************
 *	Specify the parameters for a Gaussian beam.
 ****/
void
GetGaussianBeam(BeamStruct * Beam_Ptr)
{
  Beam_Ptr->type = gaussian;

  printf("Total energy of the Gaussian beam [J]: ");
  Beam_Ptr->P = GetFloat(FLT_MIN, FLT_MAX);
  printf("1/e2 Radius of the Gaussian beam [cm]: ");
  Beam_Ptr->R = GetFloat(FLT_MIN, FLT_MAX);
  printf("Total power: %8.2lg J, and radius: %8.2lg cm.\n",
	 Beam_Ptr->P, Beam_Ptr->R);
}

/****************************************************************
 *	Specify the beam profile.
 ****/
void
LaserBeam(BeamStruct * Beam_Ptr, OutStruct * Out_Ptr)
{
  ConvStruct  null_conved = NULLCONVSTRUCT;
  char        cmd_str[STRLEN];

  printf("Beam profile:f=flat, g=Gaussian. q=quit: ");
  do
    gets(cmd_str);
  while (!strlen(cmd_str));

  switch (toupper(cmd_str[0])) {
  case 'F':
    Out_Ptr->conved = null_conved;
    GetFlatBeam(Beam_Ptr);
    break;
  case 'G':
    Out_Ptr->conved = null_conved;
    GetGaussianBeam(Beam_Ptr);
    break;
  default:;
  }
}


/****************************************************************
 *	Convolution.
 ***************************************************************/

/****************************************************************
 *	Specify the resolution and the number of points in r
 *	direction.
 *	Set the Out_Ptr->conved to null.
 *	Reallocate the arrays for the convolution arrays.
 ****/
void
ConvResolution(InputStruct * In_Ptr, OutStruct * Out_Ptr)
{
  char        in_str[STRLEN];
  ConvStruct  null_conved = NULLCONVSTRUCT;

  if (!Out_Ptr->allocated) {
    puts("...No mcml output data to work with");
    return;
  }
  printf("Current resolution: %8.2lg cm and number of points: %hd\n",
	 In_Ptr->drc, In_Ptr->nrc);
  printf("Input resolution in r direction [cm]: ");
  In_Ptr->drc = GetFloat(FLT_MIN, FLT_MAX);
  printf("Input number of points in r direction: ");
  In_Ptr->nrc = GetShort(1, SHRT_MAX);

  printf("Resolution: %8.2lg cm and number of points: %hd\n",
	 In_Ptr->drc, In_Ptr->nrc);

  Out_Ptr->conved = null_conved;
  FreeConvData(In_Ptr, Out_Ptr);
  AllocConvData(In_Ptr, Out_Ptr);
}

/****************************************************************
 *	Specify the relative convolution error. 0.001-0.1 recomended.
 *	Set the Out_Ptr->conved to null.
 ****/
void
ConvError(InputStruct * In_Ptr, OutStruct * Out_Ptr)
{
  char        in_str[STRLEN];
  ConvStruct  null_conved = NULLCONVSTRUCT;
  float       eps;

  printf("Relative convolution error\n");
  printf("Current value is %8.2g (0.001-0.1 recommended): ",
	 In_Ptr->eps);
  In_Ptr->eps = GetFloat(FLT_MIN, 1);
  Out_Ptr->conved = null_conved;
}

/***********************Binary Tree*****************************/
LINK
FillNode(float x, float y)
{
  LINK        l;

  l = (LINK) malloc(sizeof(struct Node));
  if (l) {
    l->x = x;
    l->y = y;
    l->left = l->right = NULL;
  }
  return (l);
}

/****************************************************************
 *	Assume the (x, y) is not in the tree.
 ****/
void
InsertNode(TREE * TreePtr, float x, float y)
{
  LINK        l1, l2;		/* l1 buffers l2. */

  l1 = NULL;
  l2 = *TreePtr;
  while (l2 != NULL) {
    l1 = l2;
    if (x < l2->x)
      l2 = l2->left;
    else
      l2 = l2->right;
  }

  if (l1 == NULL)		/* Empty tree. */
    *TreePtr = FillNode(x, y);
  else if (x < l1->x)
    l1->left = FillNode(x, y);
  else
    l1->right = FillNode(x, y);
}

LINK
SearchNode(TREE Tree, float x)
{
  LINK        l = Tree;
  Boolean     found = 0;

  while (l != NULL && !found)
    if (x < l->x)
      l = l->left;
    else if (x > l->x)
      l = l->right;
    else
      found = 1;

  return (l);
}

void
FreeTree(TREE Tree)
{
  if (Tree) {
    FreeTree(Tree->left);
    FreeTree(Tree->right);
    free(Tree);
  }
}

/***********************Integration*****************************/
/****************************************************************
 *	Compute Itheta shown in the manual.
 ****/
double
ITheta(double r, double r2, double R)
{
  double      temp;

  if (R >= r + r2)
    temp = 1;
  else if (fabs(r - r2) <= R) {
    temp = (r * r + r2 * r2 - R * R) / (2 * r * r2);
    if (fabs(temp) > 1)
      temp = SIGN(temp);
    temp = acos(temp) / PI;
  } else			/* R < fabs(r-r2) */
    temp = 0;

  return (temp);
}

/****************************************************************
 ****/
double
ExpBessI0(double r, double r2, double R)
{
  double      expbess;
  double      _RR = 1 / (R * R);
  double      x = 4 * r * r2 * _RR;
  double      y = 2 * (r2 * r2 + r * r) * _RR;

  expbess = exp(-y + x) * BessI0(x);
  return (expbess);
}

/****************************************************************
 *	Interpolate for the arrays A_rz[].
 ****/
double
A_rzInterp(double **A_rz, double r2)
{
  double      ir2, A_lo, A_hi, A_at_r2;
  short       iz, ir2lo, nr = ConvVar.in_ptr->nr;

  ir2 = r2 / ConvVar.in_ptr->dr;
  iz = ConvVar.iz;
  if (nr < 3)
    A_at_r2 = A_rz[0][iz];
  else if (ir2 < nr - 1.5) {	/* interpolation. */
    ir2lo = MAX(0, (short) (ir2 - 0.5));	/* truncation. */
    A_lo = A_rz[ir2lo][iz];
    A_hi = A_rz[ir2lo + 1][iz];
    A_at_r2 = A_lo + (A_hi - A_lo) * (ir2 - ir2lo - 0.5);
  } else {			/* extrapolation. */
    ir2lo = nr - 3;
    A_lo = A_rz[ir2lo][iz];
    A_hi = A_rz[ir2lo + 1][iz];
    if (A_lo >= A_hi)		/* Noise test. */
      A_at_r2 = A_lo + (A_hi - A_lo) * (ir2 - ir2lo - 0.5);
    else
      A_at_r2 = 0.0;
  }

  return (MAX(0, A_at_r2));
}

/****************************************************************
 *	Interpolate for the arrays Rd_ra[] or Tt_ra[].
 ****/
double
RT_raInterp(double **RT_ra, double r2)
{
  double      ir2, RT_lo, RT_hi, RT_at_r2;
  short       ia, ir2lo, nr = ConvVar.in_ptr->nr;

  ir2 = r2 / ConvVar.in_ptr->dr;
  ia = ConvVar.ia;
  if (nr < 3)
    RT_at_r2 = RT_ra[0][ia];
  else if (ir2 < nr - 1.5) {	/* interpolation. */
    ir2lo = MAX(0, (short) (ir2 - 0.5));	/* truncation. */
    RT_lo = RT_ra[ir2lo][ia];
    RT_hi = RT_ra[ir2lo + 1][ia];
    RT_at_r2 = RT_lo + (RT_hi - RT_lo) * (ir2 - ir2lo - 0.5);
  } else {			/* extrapolation. */
    ir2lo = nr - 3;
    RT_lo = RT_ra[ir2lo][ia];
    RT_hi = RT_ra[ir2lo + 1][ia];
    if (RT_lo >= RT_hi)		/* Noise test. */
      RT_at_r2 = RT_lo + (RT_hi - RT_lo) * (ir2 - ir2lo - 0.5);
    else
      RT_at_r2 = 0.0;
  }

  return (MAX(0, RT_at_r2));
}

/****************************************************************
 *	Interpolate for the arrays Rd_r[] or Tt_r[].
 ****/
double
RT_rInterp(double *RT_r, double r2)
{
  double      ir2, RT_lo, RT_hi, RT_at_r2;
  short       ir2lo, nr = ConvVar.in_ptr->nr;

  ir2 = r2 / ConvVar.in_ptr->dr;
  if (nr < 3)
    RT_at_r2 = RT_r[0];
  else if (ir2 < nr - 1.5) {	/* interpolation. */
    ir2lo = MAX(0, (short) (ir2 - 0.5));	/* truncation. */
    RT_lo = RT_r[ir2lo];
    RT_hi = RT_r[ir2lo + 1];
    RT_at_r2 = RT_lo + (RT_hi - RT_lo) * (ir2 - ir2lo - 0.5);
  } else {			/* extrapolation. */
    ir2lo = nr - 3;
    RT_lo = RT_r[ir2lo];
    RT_hi = RT_r[ir2lo + 1];
    if (RT_lo >= RT_hi)		/* Noise test. */
      RT_at_r2 = RT_lo + (RT_hi - RT_lo) * (ir2 - ir2lo - 0.5);
    else
      RT_at_r2 = 0.0;
  }

  return (MAX(0, RT_at_r2));
}

/****************************************************************
 *	Convolution integrand for either flat or gaussian beams.
 *	Return the integrand for the convolution integral.
 *	r2 is the r" in the formula shown in the manual.
 *	When r2 is in the range of recorded array, interpolation
 *	is used to evaluate the diffuse reflectance at r2.
 *	Note that since the last grid elements collect all the
 *	photon weight that falls beyond the grid system, we should
 *	avoid using them in the convolution.
 ****/
float
A_rzFGIntegrand(float r2)
{				/* r" in the integration. */
  float       f;
  short       nr = ConvVar.in_ptr->nr;
  double      R, r, A_at_r2;
  LINK        link;

  A_at_r2 = A_rzInterp(ConvVar.out_ptr->A_rz, r2);

  R = ConvVar.in_ptr->beam.R;
  r = ConvVar.r;
  if ((link = SearchNode(ConvVar.tree, r2)))	/* f in tree. */
    f = link->y;
  else {
    if (ConvVar.in_ptr->beam.type == flat)
      f = ITheta(r, r2, R);
    else			/* Gaussian. */
      f = ExpBessI0(r, r2, R);
    InsertNode(&ConvVar.tree, r2, f);
  }

  f *= A_at_r2 * r2;
  return (f);
}

/****************************************************************
 *	Convolution integrand for either flat or gaussian beams.
 *	See comments for A_rzFGIntegrand().
 ****/
float
Rd_raFGIntegrand(float r2)
{				/* r" in the integration. */
  float       f;
  short       nr = ConvVar.in_ptr->nr;
  double      R, r, Rd_at_r2;
  LINK        link;

  Rd_at_r2 = RT_raInterp(ConvVar.out_ptr->Rd_ra, r2);

  R = ConvVar.in_ptr->beam.R;
  r = ConvVar.r;
  if ((link = SearchNode(ConvVar.tree, r2)))	/* f in tree. */
    f = link->y;
  else {
    if (ConvVar.in_ptr->beam.type == flat)
      f = ITheta(r, r2, R);
    else			/* Gaussian. */
      f = ExpBessI0(r, r2, R);
    InsertNode(&ConvVar.tree, r2, f);
  }

  f *= Rd_at_r2 * r2;
  return (f);
}

/****************************************************************
 *	Convolution integrand for either flat or gaussian beams.
 *	See comments for A_rzFGIntegrand().
 ****/
float
Rd_rFGIntegrand(float r2)
{				/* r" in the integration. */
  float       f;
  short       nr = ConvVar.in_ptr->nr;
  double      R, r, Rd_at_r2;

  Rd_at_r2 = RT_rInterp(ConvVar.out_ptr->Rd_r, r2);

  R = ConvVar.in_ptr->beam.R;
  r = ConvVar.r;
  if (ConvVar.in_ptr->beam.type == flat)
    f = Rd_at_r2 * ITheta(r, r2, R) * r2;
  else				/* Gaussian. */
    f = Rd_at_r2 * ExpBessI0(r, r2, R) * r2;

  return (f);
}

/****************************************************************
 *	Convolution integrand for either flat or gaussian beams.
 *	See comments for A_rzFGIntegrand().
 ****/
float
Tt_raFGIntegrand(float r2)
{				/* r" in the integration. */
  float       f;
  short       nr = ConvVar.in_ptr->nr;
  double      R, r, Tt_at_r2;
  LINK        link;

  Tt_at_r2 = RT_raInterp(ConvVar.out_ptr->Tt_ra, r2);

  R = ConvVar.in_ptr->beam.R;
  r = ConvVar.r;
  if ((link = SearchNode(ConvVar.tree, r2)))	/* f in tree. */
    f = link->y;
  else {
    if (ConvVar.in_ptr->beam.type == flat)
      f = ITheta(r, r2, R);
    else			/* Gaussian. */
      f = ExpBessI0(r, r2, R);
    InsertNode(&ConvVar.tree, r2, f);
  }

  f *= Tt_at_r2 * r2;
  return (f);
}

/****************************************************************
 *	Convolution integrand for either flat or gaussian beams.
 *	See comments for A_rzFGIntegrand().
 ****/
float
Tt_rFGIntegrand(float r2)
{				/* r" in the integration. */
  float       f;
  short       nr = ConvVar.in_ptr->nr;
  double      R, r, Tt_at_r2;

  Tt_at_r2 = RT_rInterp(ConvVar.out_ptr->Tt_r, r2);

  R = ConvVar.in_ptr->beam.R;
  r = ConvVar.r;
  if (ConvVar.in_ptr->beam.type == flat)
    f = Tt_at_r2 * ITheta(r, r2, R) * r2;
  else				/* Gaussian. */
    f = Tt_at_r2 * ExpBessI0(r, r2, R) * r2;

  return (f);
}

/****************************************************************
 ****/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -