📄 convconv.c
字号:
/**************************************************************** * 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. ****/voidGetFlatBeam(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. ****/voidGetGaussianBeam(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. ****/voidLaserBeam(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. ****/voidConvResolution(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. ****/voidConvError(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*****************************/LINKFillNode(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. ****/voidInsertNode(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);}LINKSearchNode(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);}voidFreeTree(TREE Tree){ if (Tree) { FreeTree(Tree->left); FreeTree(Tree->right); free(Tree); }}/***********************Integration*****************************//**************************************************************** * Compute Itheta shown in the manual. ****/doubleITheta(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);}/**************************************************************** ****/doubleExpBessI0(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[]. ****/doubleA_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[]. ****/doubleRT_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[]. ****/doubleRT_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. ****/floatA_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(). ****/floatRd_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(). ****/floatRd_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(). ****/floatTt_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(). ****/floatTt_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 + -