[3240] | 1 | module bhmie |
---|
| 2 | use math, only: pi |
---|
| 3 | |
---|
| 4 | implicit none |
---|
| 5 | |
---|
| 6 | integer, parameter :: & |
---|
| 7 | mxnang = 1000, & ! Note: important that MXNANG be consistent with dimension of S1 and S2 in calling routine! |
---|
| 8 | s_size = 2 * MXNANG - 1 |
---|
| 9 | |
---|
| 10 | save |
---|
| 11 | |
---|
| 12 | contains |
---|
| 13 | SUBROUTINE BH_MIE(X, REFREL, NANG, S1, S2, QEXT, QSCA, QBACK, GSCA) |
---|
| 14 | implicit none |
---|
| 15 | ! Declare parameters: |
---|
| 16 | |
---|
| 17 | INTEGER NMXX |
---|
| 18 | ! PARAMETER(MXNANG=1000,NMXX=15000) |
---|
| 19 | PARAMETER(NMXX = 150000) |
---|
| 20 | ! Arguments: |
---|
| 21 | INTEGER NANG |
---|
| 22 | doubleprecision GSCA, QBACK, QEXT, QSCA, X |
---|
| 23 | COMPLEX(kind=8) REFREL |
---|
| 24 | COMPLEX(kind=8) S1(s_size), S2(s_size) |
---|
| 25 | ! Local variables: |
---|
| 26 | INTEGER J, JJ, N, NSTOP, NMX, NN |
---|
| 27 | DOUBLE PRECISION CHI, CHI0, CHI1, DANG, DX, EN, FN, P, PSI, PSI0, PSI1, & |
---|
| 28 | THETA, XSTOP, YMOD |
---|
| 29 | DOUBLE PRECISION AMU(MXNANG), pi_(MXNANG), PI0(MXNANG), PI1(MXNANG), & |
---|
| 30 | TAU(MXNANG) |
---|
| 31 | COMPLEX(kind=8) AN, AN1, BN, BN1, DREFRL, XI, XI1, Y |
---|
| 32 | COMPLEX(kind=8) D(NMXX) |
---|
| 33 | !*********************************************************************** |
---|
| 34 | ! Subroutine BHMIE is the Bohren-Huffman Mie scattering subroutine |
---|
| 35 | ! to calculate scattering and absorption by a homogenous isotropic |
---|
| 36 | ! sphere. |
---|
| 37 | ! Given: |
---|
| 38 | ! X = 2*pi*a/lambda |
---|
| 39 | ! REFREL = (complex refr. index of sphere)/(real index of medium) |
---|
| 40 | ! NANG = number of angles between 0 and 90 degrees |
---|
| 41 | ! (will calculate 2*NANG-1 directions from 0 to 180 deg.) |
---|
| 42 | ! if called with NANG<2, will set NANG=2 and will compute |
---|
| 43 | ! scattering for theta=0,90,180. |
---|
| 44 | ! Returns: |
---|
| 45 | ! S1(1 - 2*NANG-1) = -i*f_22 (incid. E perp. to scatt. plane, |
---|
| 46 | ! scatt. E perp. to scatt. plane) |
---|
| 47 | ! S2(1 - 2*NANG-1) = -i*f_11 (incid. E parr. to scatt. plane, |
---|
| 48 | ! scatt. E parr. to scatt. plane) |
---|
| 49 | ! QEXT = C_ext/pi*a**2 = efficiency factor for extinction |
---|
| 50 | ! QSCA = C_sca/pi*a**2 = efficiency factor for scattering |
---|
| 51 | ! QBACK = (dC_sca/domega)/pi*a**2 |
---|
| 52 | ! = backscattering efficiency [NB: this is (1/4*pi) smaller |
---|
| 53 | ! than the "radar backscattering efficiency"; see Bohren & |
---|
| 54 | ! Huffman 1983 pp. 120-123] |
---|
| 55 | ! GSCA = <cos(theta)> for scattering |
---|
| 56 | ! |
---|
| 57 | ! Original program taken from Bohren and Huffman (1983), Appendix A |
---|
| 58 | ! Modified by B.T.Draine, Princeton Univ. Obs., 90/10/26 |
---|
| 59 | ! in order to compute <cos(theta)> |
---|
| 60 | ! 91/05/07 (BTD): Modified to allow NANG=1 |
---|
| 61 | ! 91/08/15 (BTD): Corrected error (failure to initialize P) |
---|
| 62 | ! 91/08/15 (BTD): Modified to enhance vectorizability. |
---|
| 63 | ! 91/08/15 (BTD): Modified to make NANG=2 if called with NANG=1 |
---|
| 64 | ! 91/08/15 (BTD): Changed definition of QBACK. |
---|
| 65 | ! 92/01/08 (BTD): Converted to full double precision and double complex |
---|
| 66 | ! eliminated 2 unneed lines of code |
---|
| 67 | ! eliminated redundant variables (e.g. APSI,APSI0) |
---|
| 68 | ! renamed RN -> EN = double precision N |
---|
| 69 | ! Note that DOUBLE COMPLEX and DCMPLX are not part |
---|
| 70 | ! of f77 standard, so this version may not be fully |
---|
| 71 | ! portable. In event that portable version is |
---|
| 72 | ! needed, use src/bhmie_f77.f |
---|
| 73 | ! 93/06/01 (BTD): Changed AMAX1 to generic function MAX |
---|
| 74 | !*********************************************************************** |
---|
| 75 | !*** Safety checks |
---|
| 76 | IF(NANG>MXNANG)STOP '***Error: NANG > MXNANG in bhmie' |
---|
| 77 | IF(NANG<2)NANG = 2 |
---|
| 78 | |
---|
| 79 | DX = X |
---|
| 80 | DREFRL = REFREL |
---|
| 81 | Y = X * DREFRL |
---|
| 82 | YMOD = ABS(Y) |
---|
| 83 | ! |
---|
| 84 | !*** Series expansion terminated after NSTOP terms |
---|
| 85 | ! Logarithmic derivatives calculated from NMX on down |
---|
| 86 | XSTOP = X + 4d0 * X ** (1d0 / 3d0) + 2d0 |
---|
| 87 | NMX = int(MAX(XSTOP, YMOD)) + 15 |
---|
| 88 | ! BTD experiment 91/1/15: add one more term to series and compare results |
---|
| 89 | ! NMX=AMAX1(XSTOP,YMOD)+16 |
---|
| 90 | ! test: compute 7001 wavelengths between .0001 and 1000 micron |
---|
| 91 | ! for a=1.0micron SiC grain. When NMX increased by 1, only a single |
---|
| 92 | ! computed number changed (out of 4*7001) and it only changed by 1/8387 |
---|
| 93 | ! conclusion: we are indeed retaining enough terms in series! |
---|
| 94 | NSTOP = int(XSTOP) |
---|
| 95 | ! |
---|
| 96 | IF(NMX>NMXX)THEN |
---|
| 97 | WRITE(0, *)'Error: NMX > NMXX=', NMXX, ' for |m|x=', YMOD |
---|
| 98 | STOP |
---|
| 99 | ENDIF |
---|
| 100 | !*** Require NANG.GE.1 in order to calculate scattering intensities |
---|
| 101 | DANG = 0d0 |
---|
| 102 | IF(NANG>1)DANG = 0.5d0 * pi / DBLE(NANG - 1) |
---|
| 103 | DO J = 1, NANG |
---|
| 104 | THETA = DBLE(J - 1) * DANG |
---|
| 105 | AMU(J) = COS(THETA) |
---|
| 106 | end do |
---|
| 107 | DO J = 1, NANG |
---|
| 108 | PI0(J) = 0d0 |
---|
| 109 | PI1(J) = 1d0 |
---|
| 110 | end do |
---|
| 111 | NN = 2 * NANG - 1 |
---|
| 112 | DO J = 1, NN |
---|
| 113 | S1(J) = (0d0, 0d0) |
---|
| 114 | S2(J) = (0d0, 0d0) |
---|
| 115 | end do |
---|
| 116 | ! |
---|
| 117 | !*** Logarithmic derivative D(J) calculated by downward recurrence |
---|
| 118 | ! beginning with initial value (0.,0.) at J=NMX |
---|
| 119 | ! |
---|
| 120 | D(NMX) = (0d0, 0d0) |
---|
| 121 | NN = NMX - 1 |
---|
| 122 | DO N = 1, NN |
---|
| 123 | EN = NMX - N + 1 |
---|
| 124 | D(NMX - N) = (EN / Y) - (1. / (D(NMX - N + 1) + EN / Y)) |
---|
| 125 | end do |
---|
| 126 | ! |
---|
| 127 | !*** Riccati-Bessel functions with real argument X |
---|
| 128 | ! calculated by upward recurrence |
---|
| 129 | ! |
---|
| 130 | PSI0 = COS(DX) |
---|
| 131 | PSI1 = SIN(DX) |
---|
| 132 | CHI0 = -SIN(DX) |
---|
| 133 | CHI1 = COS(DX) |
---|
| 134 | XI1 = DCMPLX(PSI1, -CHI1) |
---|
| 135 | QSCA = 0d0 |
---|
| 136 | GSCA = 0d0 |
---|
| 137 | P = -1d0 |
---|
| 138 | DO N = 1, NSTOP |
---|
| 139 | EN = N |
---|
| 140 | FN = (2d0 * EN + 1d0) / (EN * (EN + 1d0)) |
---|
| 141 | ! for given N, PSI = psi_n CHI = chi_n |
---|
| 142 | ! PSI1 = psi_{n-1} CHI1 = chi_{n-1} |
---|
| 143 | ! PSI0 = psi_{n-2} CHI0 = chi_{n-2} |
---|
| 144 | ! Calculate psi_n and chi_n |
---|
| 145 | PSI = (2d0 * EN - 1d0) * PSI1 / DX - PSI0 |
---|
| 146 | CHI = (2d0 * EN - 1d0) * CHI1 / DX - CHI0 |
---|
| 147 | XI = DCMPLX(PSI, -CHI) |
---|
| 148 | ! |
---|
| 149 | !*** Store previous values of AN and BN for use |
---|
| 150 | ! in computation of g=<cos(theta)> |
---|
| 151 | IF(N>1)THEN |
---|
| 152 | AN1 = AN |
---|
| 153 | BN1 = BN |
---|
| 154 | ENDIF |
---|
| 155 | ! |
---|
| 156 | !*** Compute AN and BN: |
---|
| 157 | AN = (D(N) / DREFRL + EN / DX) * PSI - PSI1 |
---|
| 158 | AN = AN / ((D(N) / DREFRL + EN / DX) * XI - XI1) |
---|
| 159 | BN = (DREFRL * D(N) + EN / DX) * PSI - PSI1 |
---|
| 160 | BN = BN / ((DREFRL * D(N) + EN / DX) * XI - XI1) |
---|
| 161 | ! |
---|
| 162 | !*** Augment sums for Qsca and g=<cos(theta)> |
---|
| 163 | QSCA = QSCA + (2d0 * EN + 1d0) * (ABS(AN)**2 + ABS(BN)**2) |
---|
| 164 | GSCA = GSCA + ((2d0 * EN + 1d0) / (EN * (EN + 1d0))) * & |
---|
| 165 | (dble(AN) * dble(BN) + AIMAG(AN) * AIMAG(BN)) |
---|
| 166 | IF(N>1)THEN |
---|
| 167 | GSCA = GSCA + ((EN - 1d0) * (EN + 1d0) / EN) * & |
---|
| 168 | (dble(AN1) * dble(AN) + AIMAG(AN1) * AIMAG(AN) + & |
---|
| 169 | dble(BN1) * dble(BN) + AIMAG(BN1) * AIMAG(BN)) |
---|
| 170 | ENDIF |
---|
| 171 | ! |
---|
| 172 | !*** Now calculate scattering intensity pattern |
---|
| 173 | ! First do angles from 0 to 90 |
---|
| 174 | DO J = 1, NANG |
---|
| 175 | JJ = 2 * NANG - J |
---|
| 176 | pi_(J) = PI1(J) |
---|
| 177 | TAU(J) = EN * AMU(J) * pi_(J) - (EN + 1d0) * PI0(J) |
---|
| 178 | S1(J) = S1(J) + FN * (AN * pi_(J) + BN * TAU(J)) |
---|
| 179 | S2(J) = S2(J) + FN * (AN * TAU(J) + BN * pi_(J)) |
---|
| 180 | end do |
---|
| 181 | ! |
---|
| 182 | !*** Now do angles greater than 90 using pi_ and TAU from |
---|
| 183 | ! angles less than 90. |
---|
| 184 | ! P=1 for N=1,3,...; P=-1 for N=2,4,... |
---|
| 185 | P = -P |
---|
| 186 | DO J = 1, NANG - 1 |
---|
| 187 | JJ = 2 * NANG - J |
---|
| 188 | S1(JJ) = S1(JJ) + FN * P * (AN * pi_(J) - BN * TAU(J)) |
---|
| 189 | S2(JJ) = S2(JJ) + FN * P * (BN * pi_(J) - AN * TAU(J)) |
---|
| 190 | end do |
---|
| 191 | PSI0 = PSI1 |
---|
| 192 | PSI1 = PSI |
---|
| 193 | CHI0 = CHI1 |
---|
| 194 | CHI1 = CHI |
---|
| 195 | XI1 = DCMPLX(PSI1, -CHI1) |
---|
| 196 | ! |
---|
| 197 | !*** Compute pi_n for next value of n |
---|
| 198 | ! For each angle J, compute pi_n+1 |
---|
| 199 | ! from pi_ = pi_n , PI0 = pi_n-1 |
---|
| 200 | DO J = 1, NANG |
---|
| 201 | PI1(J) = ((2. * EN + 1.) * AMU(J) * pi_(J) - (EN + 1.) * PI0(J)) / EN |
---|
| 202 | PI0(J) = pi_(J) |
---|
| 203 | end do |
---|
| 204 | end do |
---|
| 205 | ! |
---|
| 206 | !*** Have summed sufficient terms. |
---|
| 207 | ! Now compute QSCA,QEXT,QBACK,and GSCA |
---|
| 208 | GSCA = 2d0 * GSCA / QSCA |
---|
| 209 | QSCA = (2d0 / (DX * DX)) * QSCA |
---|
| 210 | QEXT = (4d0 / (DX * DX)) * dble(S1(1)) |
---|
| 211 | QBACK = (ABS(S1(2 * NANG - 1)) / DX)**2 / pi |
---|
| 212 | RETURN |
---|
| 213 | END |
---|
| 214 | end module bhmie |
---|