1 !************************************************************************
2 ! This computer software was prepared by Battelle Memorial Institute,
3 ! hereinafter the Contractor, under Contract No. DE-AC05-76RL0 1830 with
4 ! the Department of Energy (DOE). NEITHER THE GOVERNMENT NOR THE
5 ! CONTRACTOR MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
6 ! LIABILITY FOR THE USE OF THIS SOFTWARE.
8 ! Module to Compute Aerosol Optical Properties
9 ! * Primary investigator: James C. Barnard
10 ! * Co-investigators: Rahul A. Zaveri, Richard C. Easter, William I.
12 ! Last update: February 2009
17 ! Pacific Northwest National Laboratory
18 ! P.O. Box 999, MSIN K9-30
20 ! Phone: (509) 372-6116
21 ! Email: Jerome.Fast@pnl.gov
23 ! Please report any bugs or problems to Jerome Fast, the WRF-chem
24 ! implmentation team leader for PNNL.
27 ! 1) Users are requested to consult the primary author prior to
28 ! modifying this module or incorporating it or its submodules in
29 ! another code. This is meant to ensure that the any linkages and/or
30 ! assumptions will not adversely affect the operation of this module.
31 ! 2) The source code in this module is intended for research and
32 ! educational purposes. Users are requested to contact the primary
33 ! author regarding the use of the code for any commercial application.
34 ! 3) Users preparing publications resulting from the usage of this code
35 ! are requested to cite one or more of the references below
36 ! (depending on the application) for proper acknowledgement.
38 ! Note that the aerosol optical properites are currently tied to the use
39 ! of Fast-J and MOSAIC. Future modifications will make the calculations
40 ! more generic so the code is not tied to the photolysis scheme and the
41 ! code can be used for both modal and sectional treatments.
44 ! * Fast, J.D., W.I. Gustafson Jr., R.C. Easter, R.A. Zaveri, J.C.
45 ! Barnard, E.G. Chapman, G.A. Grell, and S.E. Peckham (2005), Evolution
46 ! of ozone, particulates, and aerosol direct radiative forcing in the
47 ! vicinity of Houston using a fully-coupled meteorology-chemistry-
48 ! aerosol model, J. Geophys. Res., 111, D21305,
49 ! doi:10.1029/2005JD006721.
50 ! * Barnard, J.C., J.D. Fast, G. Paredes-Miranda, W.P. Arnott, and
51 ! A. Laskin (2010), Technical note: evaluation of the WRF-Chem
52 ! "aerosol chemical to aerosol optical properties" module using data
53 ! from the MILAGRO campaign, Atmos. Chem. Phys., 10, 7325-7340,
54 ! doi:10.5194/acp-10-7325-2010.
56 ! Contact Jerome Fast for updates on the status of manuscripts under
59 ! Additional information:
60 ! * www.pnl.gov/atmospheric/research/wrf-chem
63 ! Funding for adapting Fast-J was provided by the U.S. Department of
64 ! Energy under the auspices of Atmospheric Science Program of the Office
65 ! of Biological and Environmental Research the PNNL Laboratory Research
66 ! and Directed Research and Development program.
67 !************************************************************************
68 module module_fastj_mie
70 ! jcb 2007-feb-01 added capability to calculate aerosol backscatter
72 ! need to divide by 4*pie to get units of (km*ster)-1
73 ! jcb 2007-feb-01 now calculate true extinctionm units km^-1
76 ! rce 2005-apr-22 - want lunerr = -1 for wrf-chem 3d;
77 ! also, define lunerr here, and it's available everywhere
78 integer, parameter :: lunerr = -1
83 !***********************************************************************
85 ! Purpose: calculate aerosol optical depth, single scattering albedo,
86 ! asymmetry factor, extinction, Legendre coefficients, and average aerosol
87 ! size. parameterizes aerosol coefficients using chebychev polynomials
88 ! requires double precision on 32-bit machines
89 ! uses Wiscombe's (1979) mie scattering code
91 ! id -- grid id number
92 ! iclm, jclm -- i,j of grid column being processed
93 ! nbin_a -- number of bins
94 ! number_bin(nbin_a,kmaxd) -- number density in layer, #/cm^3
95 ! radius_wet(nbin_a,kmaxd) -- wet radius, cm
96 ! refindx(nbin_a,kmaxd) --volume averaged complex index of refraction
97 ! dz -- depth of individual cells in column, m
98 ! isecfrm0 - time from start of run, sec
99 ! lpar -- number of grid cells in vertical (via module_fastj_cmnh)
100 ! kmaxd -- predefined maximum allowed levels from module_data_mosaic_other
101 ! passed here via module_fastj_cmnh
102 ! OUTPUT: saved in module_fastj_cmnmie
103 ! real tauaer ! aerosol optical depth
104 ! waer ! aerosol single scattering albedo
105 ! gaer ! aerosol asymmetery factor
106 ! extaer ! aerosol extinction
107 ! l2,l3,l4,l5,l6,l7 ! Legendre coefficients, numbered 0,1,2,......
108 ! sizeaer ! average wet radius
109 ! bscoef ! aerosol backscatter coefficient with units km-1 * steradian -1 JCB 2007/02/01
110 !----------------------------------------------------------------------
112 id, iclm, jclm, nbin_a, &
113 number_bin, radius_wet, refindx, &
114 dz, isecfrm0, lpar, &
115 sizeaer,extaer,waer,gaer,tauaer,l2,l3,l4,l5,l6,l7,bscoef) ! added bscoef JCB 2007/02/01
117 USE module_data_mosaic_other, only : kmaxd
118 USE module_data_mosaic_therm, ONLY: nbin_a_maxd
119 USE module_peg_util, only: peg_error_fatal, peg_message
124 integer,parameter :: nspint = 4 ! Num of spectral intervals across
125 ! solar spectrum for FAST-J
126 integer, intent(in) :: lpar
127 real, dimension (nspint, kmaxd+1),intent(out) :: sizeaer,extaer,waer,gaer,tauaer
128 real, dimension (nspint, kmaxd+1),intent(out) :: l2,l3,l4,l5,l6,l7
129 real, dimension (nspint, kmaxd+1),intent(out) :: bscoef !JCB 2007/02/01
130 real, dimension (nspint),save :: wavmid !cm
132 / 0.30e-4, 0.40e-4, 0.60e-4 ,0.999e-04 /
134 integer, intent(in) :: id, iclm, jclm, nbin_a, isecfrm0
135 real, intent(in), dimension(nbin_a_maxd, kmaxd) :: number_bin
136 real, intent(inout), dimension(nbin_a_maxd, kmaxd) :: radius_wet
137 complex, intent(in) :: refindx(nbin_a_maxd, kmaxd)
138 real, intent(in) :: dz(lpar)
141 real weighte, weights
142 ! various bookeeping variables
143 integer ltype ! total number of indicies of refraction
144 parameter (ltype = 1) ! bracket refractive indices based on information from Rahul, 2002/11/07
146 real thesum ! for normalizing things
147 real sizem ! size in microns
150 integer m, j, nc, klevel
151 real pext ! parameterized specific extinction (cm2/g)
152 real pasm ! parameterized asymmetry factor
153 real ppmom2 ! 2 Lengendre expansion coefficient (numbered 0,1,2,...)
159 real sback2 ! JCB 2007/02/01 sback*conjg(sback)
161 integer ns ! Spectral loop index
162 integer i ! Longitude loop index
163 integer k ! Level loop index
164 real pscat !scattering cross section
166 integer prefr,prefi,nrefr,nrefi,nr,ni
168 parameter (prefr=7,prefi=7)
170 complex*16 sforw,sback,tforw(2),tback(2)
171 integer numang,nmom,ipolzn,momdim
173 logical perfct,anyang,prnt(2)
175 integer, parameter :: nsiz=200,nlog=30,ncoef=50
177 real p2(nsiz),p3(nsiz),p4(nsiz),p5(nsiz)
178 real p6(nsiz),p7(nsiz)
181 data xmu/1./,anyang/.false./
183 complex*16 s1(1),s2(1)
187 data perfct/.false./,mimcut/0.0/
188 data nmom/7/,ipolzn/0/,momdim/7/
189 data prnt/.false.,.false./
190 ! coefficients for parameterizing aerosol radiative properties
191 ! in terms of refractive index and wet radius
192 real extp(ncoef,prefr,prefi,nspint) ! specific extinction
193 real albp(ncoef,prefr,prefi,nspint) ! single scat alb
194 real asmp(ncoef,prefr,prefi,nspint) ! asymmetry factor
195 real ascat(ncoef,prefr,prefi,nspint) ! scattering efficiency, JCB 2004/02/09
196 real pmom2(ncoef,prefr,prefi,nspint) ! phase function expansion, #2
197 real pmom3(ncoef,prefr,prefi,nspint) ! phase function expansion, #3
198 real pmom4(ncoef,prefr,prefi,nspint) ! phase function expansion, #4
199 real pmom5(ncoef,prefr,prefi,nspint) ! phase function expansion, #5
200 real pmom6(ncoef,prefr,prefi,nspint) ! phase function expansion, #6
201 real pmom7(ncoef,prefr,prefi,nspint) ! phase function expansion, #7
202 real sback2p(ncoef,prefr,prefi,nspint) ! JCB 2007/02/01 - backscatter
204 save :: extp,albp,asmp,ascat,pmom2,pmom3,pmom4,pmom5,pmom6,pmom7,sback2p ! JCB 2007/02/01 - added sback2p
206 real cext(ncoef),casm(ncoef),cpmom2(ncoef)
207 real cscat(ncoef) ! JCB 2004/02/09
208 real cpmom3(ncoef),cpmom4(ncoef),cpmom5(ncoef)
209 real cpmom6(ncoef),cpmom7(ncoef)
210 real cpsback2p(ncoef) ! JCB 2007/02/09 - backscatter
214 ! nsiz = number of wet particle sizes
215 ! crefin = complex refractive index
217 real*8 thesize ! 2 pi radpart / waveleng = size parameter
218 real*8 qext(nsiz) ! array of extinction efficiencies
219 real*8 qsca(nsiz) ! array of scattering efficiencies
220 real*8 gqsc(nsiz) ! array of asymmetry factor * scattering efficiency
221 real asymm(nsiz) ! array of asymmetry factor
222 real scat(nsiz) ! JCB 2004/02/09
223 real sb2(nsiz) ! JCB 2007/02/01 - 4*abs(sback)^2/(size parameter)^2 backscattering efficiency
224 ! specabs = absorption coeff / unit dry mass
225 ! specscat = scattering coeff / unit dry mass
226 complex*16 crefin,crefd,crefw
228 real, save :: rmin,rmax ! min, max aerosol size bin
229 data rmin /0.005e-4/ ! rmin in cm. 5e-3 microns min allowable size
230 data rmax /50.e-4 / ! rmax in cm. 50 microns, big particle, max allowable size
234 real, save :: xrmin,xrmax,xr
235 real rs(nsiz) ! surface mode radius (cm)
236 real xrad ! normalized aerosol radius
237 real ch(ncoef) ! chebychev polynomial
239 real, save :: rhoh2o ! density of liquid water (g/cm3)
242 real refr ! real part of refractive index
243 real refi ! imaginary part of refractive index
244 real qextr4(nsiz) ! extinction, real*4
246 real refrmin ! minimum of real part of refractive index
247 real refrmax ! maximum of real part of refractive index
248 real refimin ! minimum of imag part of refractive index
249 real refimax ! maximum of imag part of refractive index
250 real drefr ! increment in real part of refractive index
251 real drefi ! increment in imag part of refractive index
252 real, save :: refrtab(prefr) ! table of real refractive indices for aerosols
253 real, save :: refitab(prefi) ! table of imag refractive indices for aerosols
254 complex specrefndx(ltype) ! refractivr indices
258 ! diagnostic declarations
263 #if (defined(CHEM_DBG_I) && defined(CHEM_DBG_J) && defined(CHEM_DBG_K))
264 !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
266 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
267 !ec run_out.25 has aerosol physical parameter info for bins 1-8
268 !ec and vertical cells 1 to kmaxd.
271 if (iclm .eq. CHEM_DBG_I) then
272 if (jclm .eq. CHEM_DBG_J) then
274 if (kcallmieaer2 .eq. 0) then
275 write(*,9099)iclm, jclm
276 9099 format('for cell i = ', i3, 2x, 'j = ', i3)
279 'isecfrm0', 3x, 'i', 3x, 'j', 3x,'k', 3x, &
281 'refindx(ibin,k)', 3x, &
282 'radius_wet(ibin,k)', 3x, &
283 'number_bin(ibin,k)' &
286 !ec output for run_out.25
290 isecfrm0,iclm, jclm, k, ibin, &
292 radius_wet(ibin,k), &
294 9120 format( i7,3(2x,i4),2x,i4, 4x, 4(e14.6,2x))
297 kcallmieaer2 = kcallmieaer2 + 1
300 !ec end print of aerosol physical parameter diagnostics
301 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
304 ! assign fast-J wavelength, these values are in cm
308 ! wavmid(4)=0.999e-04
315 ! parameterize aerosol radiative properties in terms of
316 ! relative humidity, surface mode wet radius, aerosol species,
319 ! first find min,max of real and imaginary parts of refractive index
321 ! real and imaginary parts of water refractive index
323 crefw=cmplx(1.33,0.0)
326 ! change Rahul's imaginary part of the refractive index from positive to negative
331 specrefndx(1)=cmplx(1.82,-0.74) ! max values from Rahul, 7 Nov 2002
334 do i=1,ltype ! loop over all possible refractive indices
336 ! real and imaginary parts of aerosol refractive index
338 refrmin=amin1(refrmin,real(specrefndx(ltype)))
339 refrmax=amax1(refrmax,real(specrefndx(ltype)))
340 refimin=amin1(refimin,aimag(specrefndx(ltype)))
341 refimax=amax1(refimax,aimag(specrefndx(ltype)))
345 drefr=(refrmax-refrmin)
346 if(drefr.gt.1.e-4)then
348 drefr=drefr/(nrefr-1)
353 drefi=(refimax-refimin)
354 if(drefi.gt.1.e-4)then
356 drefi=drefi/(nrefi-1)
363 bma=0.5*alog(rmax/rmin) ! JCB
364 bpa=0.5*alog(rmax*rmin) ! JCB
372 ! calibrate parameterization with range of refractive indices
377 refrtab(nr)=refrmin+(nr-1)*drefr
378 refitab(ni)=refimin+(ni-1)*drefi
379 crefd=cmplx(refrtab(nr),refitab(ni))
381 ! mie calculations of optical efficiencies
384 xr=cos(pie*(float(n)-0.5)/float(nsiz))
385 rs(n)=exp(xr*bma+bpa)
388 ! size parameter and weighted refractive index
390 thesize=2.*pie*rs(n)/wavmid(ns)
391 thesize=min(thesize,10000.d0)
393 call miev0(thesize,crefd,perfct,mimcut,anyang, &
394 numang,xmu,nmom,ipolzn,momdim,prnt, &
395 qext(n),qsca(n),gqsc(n),pmom,sforw,sback,s1, &
398 ! qabs(n)=qext(n)-qsca(n) ! not necessary anymore JCB 2004/02/09
399 scat(n)=qsca(n) ! JCB 2004/02/09
400 asymm(n)=gqsc(n)/qsca(n) ! assume always greater than zero
401 ! coefficients of phase function expansion; note modification by JCB of miev0 coefficients
402 p2(n)=pmom(2,1)/pmom(0,1)*5.0
403 p3(n)=pmom(3,1)/pmom(0,1)*7.0
404 p4(n)=pmom(4,1)/pmom(0,1)*9.0
405 p5(n)=pmom(5,1)/pmom(0,1)*11.0
406 p6(n)=pmom(6,1)/pmom(0,1)*13.0
407 p7(n)=pmom(7,1)/pmom(0,1)*15.0
408 ! backscattering efficiency, Bohren and Huffman, page 122
409 ! as stated by Bohren and Huffman, this is 4*pie times what is should be
410 ! may need to be smoothed - a very rough function - for the time being we won't apply smoothing
411 ! and let the integration over the size distribution be the smoothing
412 sb2(n)=4.0*sback*dconjg(sback)/(thesize*thesize) ! JCB 2007/02/01
416 call fitcurv(rs,qextr4,extp(1,nr,ni,ns),ncoef,nsiz)
417 call fitcurv(rs,scat,ascat(1,nr,ni,ns),ncoef,nsiz) ! JCB 2004/02/07 - scattering efficiency
418 call fitcurv(rs,asymm,asmp(1,nr,ni,ns),ncoef,nsiz)
419 call fitcurv_nolog(rs,p2,pmom2(1,nr,ni,ns),ncoef,nsiz)
420 call fitcurv_nolog(rs,p3,pmom3(1,nr,ni,ns),ncoef,nsiz)
421 call fitcurv_nolog(rs,p4,pmom4(1,nr,ni,ns),ncoef,nsiz)
422 call fitcurv_nolog(rs,p5,pmom5(1,nr,ni,ns),ncoef,nsiz)
423 call fitcurv_nolog(rs,p6,pmom6(1,nr,ni,ns),ncoef,nsiz)
424 call fitcurv_nolog(rs,p7,pmom7(1,nr,ni,ns),ncoef,nsiz)
425 call fitcurv(rs,sb2,sback2p(1,nr,ni,ns),ncoef,nsiz) ! JCB 2007/02/01 - backscattering efficiency
433 do 2000 klevel=1,lpar
434 ! sum densities for normalization
437 thesum=thesum+number_bin(m,klevel)
439 ! Begin spectral loop
442 ! aerosol optical properties
447 sizeaer(ns,klevel)=0.0
448 extaer(ns,klevel)=0.0
455 bscoef(ns,klevel)=0.0 ! JCB 2007/02/01 - backscattering coefficient
456 if(thesum.le.1e-21)goto 1000 ! set everything = 0 if no aerosol !wig changed 0.0 to 1e-21, 31-Oct-2005
459 do m=1,nbin_a ! nbin_a is number of bins
460 ! check to see if there's any aerosol
461 if(number_bin(m,klevel).le.1e-21)goto 70 ! no aerosol !wig changed 0.0 to 1e-21, 31-Oct-2005
463 sizem=radius_wet(m,klevel) ! radius in cm
464 ! check limits of particle size
465 ! rce 2004-dec-07 - use klevel in write statements
466 if(radius_wet(m,klevel).le.rmin)then
467 radius_wet(m,klevel)=rmin
468 write( msg, '(a, 5i4,1x, e11.4)' ) &
469 'FASTJ mie: radius_wet set to rmin,' // &
470 'id,i,j,k,m,rm(m,k)', id, iclm, jclm, klevel, m, radius_wet(m,klevel)
471 call peg_message( lunerr, msg )
472 ! write(6,'('' particle size too small '')')
475 if(radius_wet(m,klevel).gt.rmax)then
476 write( msg, '(a, 5i4,1x, e11.4)' ) &
477 'FASTJ mie: radius_wet set to rmax,' // &
478 'id,i,j,k,m,rm(m,k)', &
479 id, iclm, jclm, klevel, m, radius_wet(m,klevel)
480 call peg_message( lunerr, msg )
481 radius_wet(m,klevel)=rmax
482 ! write(6,'('' particle size too large '')')
485 x=alog(radius_wet(m,klevel)) ! radius in cm
487 crefin=refindx(m,klevel)
489 ! change Rahul's imaginary part of the index of refraction from positive to negative
494 thesize=2.0*pie*exp(x)/wavmid(ns)
495 ! normalize size parameter
496 xrad=(2*xrad-xrmax-xrmin)/(xrmax-xrmin)
497 ! retain this diagnostic code
498 if(abs(refr).gt.10.0.or.abs(refr).le.0.001)then
499 write ( msg, '(a,1x, e14.5)' ) &
500 'FASTJ mie /refr/ outside range 1e-3 - 10 ' // &
502 ! print *,'refr=',refr
503 call peg_error_fatal( lunerr, msg )
505 if(abs(refi).gt.10.)then
506 write ( msg, '(a,1x, e14.5)' ) &
507 'FASTJ mie /refi/ >10 ' // &
509 ! print *,'refi=',refi
510 call peg_error_fatal( lunerr, msg )
513 ! interpolate coefficients linear in refractive index
514 ! first call calcs itab,jtab,ttab,utab
516 call binterp(extp(1,1,1,ns),ncoef,nrefr,nrefi, &
517 refr,refi,refrtab,refitab,itab,jtab, &
520 ! JCB 2004/02/09 -- new code for scattering cross section
521 call binterp(ascat(1,1,1,ns),ncoef,nrefr,nrefi, &
522 refr,refi,refrtab,refitab,itab,jtab, &
524 call binterp(asmp(1,1,1,ns),ncoef,nrefr,nrefi, &
525 refr,refi,refrtab,refitab,itab,jtab, &
527 call binterp(pmom2(1,1,1,ns),ncoef,nrefr,nrefi, &
528 refr,refi,refrtab,refitab,itab,jtab, &
530 call binterp(pmom3(1,1,1,ns),ncoef,nrefr,nrefi, &
531 refr,refi,refrtab,refitab,itab,jtab, &
533 call binterp(pmom4(1,1,1,ns),ncoef,nrefr,nrefi, &
534 refr,refi,refrtab,refitab,itab,jtab, &
536 call binterp(pmom5(1,1,1,ns),ncoef,nrefr,nrefi, &
537 refr,refi,refrtab,refitab,itab,jtab, &
539 call binterp(pmom6(1,1,1,ns),ncoef,nrefr,nrefi, &
540 refr,refi,refrtab,refitab,itab,jtab, &
542 call binterp(pmom7(1,1,1,ns),ncoef,nrefr,nrefi, &
543 refr,refi,refrtab,refitab,itab,jtab, &
545 call binterp(sback2p(1,1,1,ns),ncoef,nrefr,nrefi, &
546 refr,refi,refrtab,refitab,itab,jtab, &
549 ! chebyshev polynomials
554 ch(nc)=2.*xrad*ch(nc-1)-ch(nc-2)
556 ! parameterized optical properties
560 pext=pext+ch(nc)*cext(nc)
564 ! JCB 2004/02/09 -- for scattering efficiency
567 pscat=pscat+ch(nc)*cscat(nc)
573 pasm=pasm+ch(nc)*casm(nc)
579 ppmom2=ppmom2+ch(nc)*cpmom2(nc)
581 if(ppmom2.le.0.0)ppmom2=0.0
585 ppmom3=ppmom3+ch(nc)*cpmom3(nc)
587 ! ppmom3=exp(ppmom3) ! no exponentiation required
588 if(ppmom3.le.0.0)ppmom3=0.0
592 ppmom4=ppmom4+ch(nc)*cpmom4(nc)
594 if(ppmom4.le.0.0.or.sizem.le.0.03e-04)ppmom4=0.0
598 ppmom5=ppmom5+ch(nc)*cpmom5(nc)
600 if(ppmom5.le.0.0.or.sizem.le.0.03e-04)ppmom5=0.0
604 ppmom6=ppmom6+ch(nc)*cpmom6(nc)
606 if(ppmom6.le.0.0.or.sizem.le.0.03e-04)ppmom6=0.0
610 ppmom7=ppmom7+ch(nc)*cpmom7(nc)
612 if(ppmom7.le.0.0.or.sizem.le.0.03e-04)ppmom7=0.0
614 sback2=0.5*cpsback2p(1) ! JCB 2007/02/01 - backscattering efficiency
616 sback2=sback2+ch(nc)*cpsback2p(nc)
619 if(sback2.le.0.0)sback2=0.0
623 weighte=pext*pie*exp(x)**2 ! JCB, extinction cross section
624 weights=pscat*pie*exp(x)**2 ! JCB, scattering cross section
625 tauaer(ns,klevel)=tauaer(ns,klevel)+weighte*number_bin(m,klevel) ! must be multiplied by deltaZ
626 ! extaer(ns,klevel)=extaer(ns,klevel)+pext*number_bin(m,klevel) ! not the true extinction, JCB 2007/02/01
627 sizeaer(ns,klevel)=sizeaer(ns,klevel)+exp(x)*10000.0* &
629 waer(ns,klevel)=waer(ns,klevel)+weights*number_bin(m,klevel) !JCB
630 gaer(ns,klevel)=gaer(ns,klevel)+pasm*weights* &
631 number_bin(m,klevel) !JCB
632 ! need weighting by scattering cross section ? JCB 2004/02/09
633 l2(ns,klevel)=l2(ns,klevel)+weights*ppmom2*number_bin(m,klevel)
634 l3(ns,klevel)=l3(ns,klevel)+weights*ppmom3*number_bin(m,klevel)
635 l4(ns,klevel)=l4(ns,klevel)+weights*ppmom4*number_bin(m,klevel)
636 l5(ns,klevel)=l5(ns,klevel)+weights*ppmom5*number_bin(m,klevel)
637 l6(ns,klevel)=l6(ns,klevel)+weights*ppmom6*number_bin(m,klevel)
638 l7(ns,klevel)=l7(ns,klevel)+weights*ppmom7*number_bin(m,klevel)
639 ! convert backscattering efficiency to backscattering coefficient, units (cm)^-1
640 bscoef(ns,klevel)=bscoef(ns,klevel)+pie*exp(x)**2*sback2*number_bin(m,klevel) ! JCB 2007/02/01 - backscatter coefficient,
642 end do ! end of nbin_a loop
643 ! take averages - weighted by cross section - new code JCB 2004/02/09
644 sizeaer(ns,klevel)=sizeaer(ns,klevel)/thesum
645 gaer(ns,klevel)=gaer(ns,klevel)/waer(ns,klevel) ! JCB removed *3 factor 2/9/2004
646 ! because factor is applied in subroutine opmie, file zz01fastj_mod.f
647 l2(ns,klevel)=l2(ns,klevel)/waer(ns,klevel)
648 l3(ns,klevel)=l3(ns,klevel)/waer(ns,klevel)
649 l4(ns,klevel)=l4(ns,klevel)/waer(ns,klevel)
650 l5(ns,klevel)=l5(ns,klevel)/waer(ns,klevel)
651 l6(ns,klevel)=l6(ns,klevel)/waer(ns,klevel)
652 l7(ns,klevel)=l7(ns,klevel)/waer(ns,klevel)
653 ! backscatter coef, divide by 4*Pie to get units of (km*ster)^-1 JCB 2007/02/01
654 bscoef(ns,klevel)=bscoef(ns,klevel)*1.0e5 ! JCB 2007/02/01 - units are now (km)^-1
655 extaer(ns,klevel)=tauaer(ns,klevel)*1.0e5 ! JCB 2007/02/01 - now true extincion, units (km)^-1
656 ! this must be last!! JCB 2007/02/01
657 waer(ns,klevel)=waer(ns,klevel)/tauaer(ns,klevel) ! JCB
659 70 continue ! bail out if no aerosol;go on to next wavelength bin
661 1000 continue ! end of wavelength loop
664 2000 continue ! end of klevel loop
666 ! before returning, multiply tauaer by depth of individual cells.
667 ! tauaer is in cm-1, dz in m; multiply dz by 100 to convert from m to cm.
670 tauaer(ns,klevel) = tauaer(ns,klevel) * dz(klevel)* 100.
674 #if (defined(CHEM_DBG_I) && defined(CHEM_DBG_J) && defined(CHEM_DBG_K))
675 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
676 !ec fastj diagnostics
677 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
678 !ec run_out.30 has aerosol optical info for cells 1 to kmaxd.
681 if (iclm .eq. CHEM_DBG_I) then
682 if (jclm .eq. CHEM_DBG_J) then
684 if (kcallmieaer .eq. 0) then
685 write(*,909) CHEM_DBG_I, CHEM_DBG_J
686 909 format( ' for cell i = ', i3, ' j = ', i3)
689 'isecfrm0', 3x, 'i', 3x, 'j', 3x,'k', 3x, &
691 'tauaer(1,k)',1x, 'tauaer(2,k)',1x,'tauaer(3,k)',3x, &
693 'waer(1,k)', 7x, 'waer(2,k)', 7x,'waer(3,k)', 7x, &
695 'gaer(1,k)', 7x, 'gaer(2,k)', 7x,'gaer(3,k)', 7x, &
697 'extaer(1,k)',5x, 'extaer(2,k)',5x,'extaer(3,k)',5x, &
699 'sizeaer(1,k)',4x, 'sizeaer(2,k)',4x,'sizeaer(3,k)',4x, &
702 !ec output for run_out.30
705 isecfrm0,iclm, jclm, k, &
707 (tauaer(n,k), n=1,4), &
708 (waer(n,k), n=1,4), &
709 (gaer(n,k), n=1,4), &
710 (extaer(n,k), n=1,4), &
711 (sizeaer(n,k), n=1,4)
712 912 format( i7,3(2x,i4),2x,21(e14.6,2x))
714 kcallmieaer = kcallmieaer + 1
717 !ec end print of fastj diagnostics
718 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
722 end subroutine mieaer
723 !****************************************************************
724 subroutine fitcurv(rs,yin,coef,ncoef,maxm)
726 ! fit y(x) using Chebychev polynomials
727 ! wig 7-Sep-2004: Removed dependency on pre-determined maximum
728 ! array size and replaced with f90 array info.
730 USE module_peg_util, only: peg_message
733 ! integer nmodes, nrows, maxm, ncoef
734 ! parameter (nmodes=500,nrows=8)
735 integer, intent(in) :: maxm, ncoef
737 ! real rs(nmodes),yin(nmodes),coef(ncoef)
738 ! real x(nmodes),y(nmodes)
739 real, dimension(ncoef) :: coef
740 real, dimension(:) :: rs, yin
741 real x(size(rs)),y(size(yin))
747 !!$ if(maxm.gt.nmodes)then
748 !!$ write ( msg, '(a, 1x,i6)' ) &
749 !!$ 'FASTJ mie nmodes too small in fitcurv, ' // &
751 !!$! write(*,*)'nmodes too small in fitcurv',maxm
752 !!$ call peg_error_fatal( lunerr, msg )
763 x(m)=(2*x(m)-xmax-xmin)/(xmax-xmin)
766 call chebft(coef,ncoef,maxm,y)
769 end subroutine fitcurv
770 !**************************************************************
771 subroutine fitcurv_nolog(rs,yin,coef,ncoef,maxm)
773 ! fit y(x) using Chebychev polynomials
774 ! wig 7-Sep-2004: Removed dependency on pre-determined maximum
775 ! array size and replaced with f90 array info.
777 USE module_peg_util, only: peg_message
780 ! integer nmodes, nrows, maxm, ncoef
781 ! parameter (nmodes=500,nrows=8)
782 integer, intent(in) :: maxm, ncoef
784 ! real rs(nmodes),yin(nmodes),coef(ncoef)
785 real, dimension(:) :: rs, yin
786 real, dimension(ncoef) :: coef(ncoef)
787 real x(size(rs)),y(size(yin))
793 !!$ if(maxm.gt.nmodes)then
794 !!$ write ( msg, '(a,1x, i6)' ) &
795 !!$ 'FASTJ mie nmodes too small in fitcurv ' // &
797 !!$! write(*,*)'nmodes too small in fitcurv',maxm
798 !!$ call peg_error_fatal( lunerr, msg )
803 y(m)=yin(m) ! note, no "alog" here
809 x(m)=(2*x(m)-xmax-xmin)/(xmax-xmin)
812 call chebft(coef,ncoef,maxm,y)
815 end subroutine fitcurv_nolog
816 !************************************************************************
817 subroutine chebft(c,ncoef,n,f)
818 ! given a function f with values at zeroes x_k of Chebychef polynomial
819 ! T_n(x), calculate coefficients c_j such that
820 ! f(x)=sum(k=1,n) c_k t_(k-1)(y) - 0.5*c_1
821 ! where y=(x-0.5*(xmax+xmin))/(0.5*(xmax-xmin))
822 ! See Numerical Recipes, pp. 148-150.
827 parameter (pi=3.14159265)
838 thesum=thesum+f(k)*cos((pi*(j-1))*((k-0.5)/n))
843 end subroutine chebft
844 !*************************************************************************
845 subroutine binterp(table,km,im,jm,x,y,xtab,ytab,ix,jy,t,u,out)
847 ! bilinear interpolation of table
851 real table(km,im,jm),xtab(im),ytab(jm),out(km)
852 integer i,ix,ip1,j,jy,jp1,k
853 real x,dx,t,y,dy,u,tu, tuc,tcu,tcuc
858 if(x.lt.xtab(i))go to 10
862 dx=(xtab(ip1)-xtab(ix))
863 if(abs(dx).gt.1.e-20)then
864 t=(x-xtab(ix))/(xtab(ix+1)-xtab(ix))
875 if(y.lt.ytab(j))go to 20
879 dy=(ytab(jp1)-ytab(jy))
880 if(abs(dy).gt.1.e-20)then
898 out(k)=tcuc*table(k,ix,jy)+tuc*table(k,ip1,jy) &
899 +tu*table(k,ip1,jp1)+tcu*table(k,ix,jp1)
902 end subroutine binterp
903 !***************************************************************
904 subroutine miev0 ( xx, crefin, perfct, mimcut, anyang, &
905 numang, xmu, nmom, ipolzn, momdim, prnt, &
906 qext, qsca, gqsc, pmom, sforw, sback, s1, &
909 ! computes mie scattering and extinction efficiencies; asymmetry
910 ! factor; forward- and backscatter amplitude; scattering
911 ! amplitudes for incident polarization parallel and perpendicular
912 ! to the plane of scattering, as functions of scattering angle;
913 ! coefficients in the legendre polynomial expansions of either the
914 ! unpolarized phase function or the polarized phase matrix;
915 ! and some quantities needed in polarized radiative transfer.
917 ! calls : biga, ckinmi, small1, small2, testmi, miprnt,
920 ! i n t e r n a l v a r i a b l e s
921 ! -----------------------------------
923 ! an,bn mie coefficients little-a-sub-n, little-b-sub-n
925 ! anm1,bnm1 mie coefficients little-a-sub-(n-1),
926 ! little-b-sub-(n-1); used in -gqsc- sum
927 ! anp coeffs. in s+ expansion ( ref. 2, p. 1507 )
928 ! bnp coeffs. in s- expansion ( ref. 2, p. 1507 )
929 ! anpm coeffs. in s+ expansion ( ref. 2, p. 1507 )
930 ! when mu is replaced by - mu
931 ! bnpm coeffs. in s- expansion ( ref. 2, p. 1507 )
932 ! when mu is replaced by - mu
933 ! calcmo(k) true, calculate moments for k-th phase quantity
934 ! (derived from -ipolzn-; used only in 'lpcoef')
935 ! cbiga(n) bessel function ratio capital-a-sub-n (ref. 2, eq. 2)
936 ! ( complex version )
937 ! cior complex index of refraction with negative
938 ! imaginary part (van de hulst convention)
940 ! coeff ( 2n + 1 ) / ( n ( n + 1 ) )
941 ! fn floating point version of index in loop performing
942 ! mie series summation
943 ! lita,litb(n) mie coefficients -an-, -bn-, saved in arrays for
944 ! use in calculating legendre moments *pmom*
945 ! maxtrm max. possible no. of terms in mie series
946 ! mm + 1 and - 1, alternately.
947 ! mim magnitude of imaginary refractive index
948 ! mre real part of refractive index
949 ! maxang max. possible value of input variable -numang-
950 ! nangd2 (numang+1)/2 ( no. of angles in 0-90 deg; anyang=f )
951 ! noabs true, sphere non-absorbing (determined by -mimcut-)
952 ! np1dn ( n + 1 ) / n
953 ! npquan highest-numbered phase quantity for which moments are
954 ! to be calculated (the largest digit in -ipolzn-
956 ! ntrm no. of terms in mie series
957 ! pass1 true on first entry, false thereafter; for self-test
958 ! pin(j) angular function little-pi-sub-n ( ref. 2, eq. 3 )
960 ! pinm1(j) little-pi-sub-(n-1) ( see -pin- ) at j-th angle
961 ! psinm1 ricatti-bessel function psi-sub-(n-1), argument -xx-
962 ! psin ricatti-bessel function psi-sub-n of argument -xx-
963 ! ( ref. 1, p. 11 ff. )
964 ! rbiga(n) bessel function ratio capital-a-sub-n (ref. 2, eq. 2)
965 ! ( real version, for when imag refrac index = 0 )
968 ! rtmp (real) temporary variable
969 ! sp(j) s+ for j-th angle ( ref. 2, p. 1507 )
970 ! sm(j) s- for j-th angle ( ref. 2, p. 1507 )
971 ! sps(j) s+ for (numang+1-j)-th angle ( anyang=false )
972 ! sms(j) s- for (numang+1-j)-th angle ( anyang=false )
973 ! taun angular function little-tau-sub-n ( ref. 2, eq. 4 )
975 ! tcoef n ( n+1 ) ( 2n+1 ) (for summing tforw,tback series)
977 ! yesang true if scattering amplitudes are to be calculated
978 ! zetnm1 ricatti-bessel function zeta-sub-(n-1) of argument
979 ! -xx- ( ref. 2, eq. 17 )
980 ! zetn ricatti-bessel function zeta-sub-n of argument -xx-
982 ! ----------------------------------------------------------------------
983 ! -------- i / o specifications for subroutine miev0 -----------------
984 ! ----------------------------------------------------------------------
986 logical anyang, perfct, prnt(*)
987 integer ipolzn, momdim, numang, nmom
988 real*8 gqsc, mimcut, pmom( 0:momdim, * ), qext, qsca, &
990 complex*16 crefin, sforw, sback, s1(*), s2(*), tforw(*), &
992 integer maxang,mxang2,maxtrm
994 ! ----------------------------------------------------------------------
996 parameter ( maxang = 501, mxang2 = maxang/2 + 1 )
998 ! ** note -- maxtrm = 10100 is neces-
999 ! ** sary to do some of the test probs,
1000 ! ** but 1100 is sufficient for most
1001 ! ** conceivable applications
1002 parameter ( maxtrm = 1100 )
1003 parameter ( onethr = 1./3. )
1005 logical anysav, calcmo(4), noabs, ok, pass1, persav, yesang
1007 integer i,j,n,nmosav,iposav,numsav,ntrm,nangd2
1008 real*8 mim, mimsav, mre, mm, np1dn
1009 real*8 rioriv,xmusav,xxsav,sq,fn,rn,twonp1,tcoef, coeff
1010 real*8 xinv,psinm1,chinm1,psin,chin,rtmp,taun
1011 real*8 rbiga( maxtrm ), pin( maxang ), pinm1( maxang )
1012 complex*16 an, bn, anm1, bnm1, anp, bnp, anpm, bnpm, cresav, &
1013 cior, cioriv, ctmp, zet, zetnm1, zetn
1014 complex*16 cbiga( maxtrm ), lita( maxtrm ), litb( maxtrm ), &
1015 sp( maxang ), sm( maxang ), sps( mxang2 ), sms( mxang2 )
1016 equivalence ( cbiga, rbiga )
1018 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
1019 data pass1 / .true. /
1023 ! ** save certain user input values
1033 ! ** reset input values for test case
1035 crefin = ( 1.5, - 0.1 )
1040 xmu( 1 )= - 0.7660444
1045 ! ** check input and calculate
1046 ! ** certain variables from input
1048 10 call ckinmi( numang, maxang, xx, perfct, crefin, momdim, &
1049 nmom, ipolzn, anyang, xmu, calcmo, npquan )
1051 if ( perfct .and. xx .le. 0.1 ) then
1052 ! ** use totally-reflecting
1053 ! ** small-particle limit
1055 call small1 ( xx, numang, xmu, qext, qsca, gqsc, sforw, &
1056 sback, s1, s2, tforw, tback, lita, litb )
1061 if ( .not.perfct ) then
1064 if ( dimag( cior ) .gt. 0.0 ) cior = dconjg( cior )
1066 mim = - dimag( cior )
1067 noabs = mim .le. mimcut
1071 if ( xx * dmax1( 1.d0, cdabs(cior) ) .le. 0.d1 ) then
1073 ! ** use general-refractive-index
1074 ! ** small-particle limit
1075 ! ** ( ref. 2, p. 1508 )
1077 call small2 ( xx, cior, .not.noabs, numang, xmu, qext, &
1078 qsca, gqsc, sforw, sback, s1, s2, tforw, &
1086 nangd2 = ( numang + 1 ) / 2
1087 yesang = numang .gt. 0
1088 ! ** estimate number of terms in mie series
1089 ! ** ( ref. 2, p. 1508 )
1090 if ( xx.le.8.0 ) then
1091 ntrm = xx + 4. * xx**onethr + 1.
1092 else if ( xx.lt.4200. ) then
1093 ntrm = xx + 4.05 * xx**onethr + 2.
1095 ntrm = xx + 4. * xx**onethr + 2.
1097 if ( ntrm+1 .gt. maxtrm ) &
1098 call errmsg( 'miev0--parameter maxtrm too small', .true. )
1100 ! ** calculate logarithmic derivatives of
1101 ! ** j-bessel-fcn., big-a-sub-(1 to ntrm)
1102 if ( .not.perfct ) &
1103 call biga( cior, xx, ntrm, noabs, yesang, rbiga, cbiga )
1105 ! ** initialize ricatti-bessel functions
1106 ! ** (psi,chi,zeta)-sub-(0,1) for upward
1107 ! ** recurrence ( ref. 1, eq. 19 )
1111 psin = psinm1 * xinv - chinm1
1112 chin = chinm1 * xinv + psinm1
1113 zetnm1 = dcmplx( psinm1, chinm1 )
1114 zetn = dcmplx( psin, chin )
1115 ! ** initialize previous coeffi-
1116 ! ** cients for -gqsc- series
1119 ! ** initialize angular function little-pi
1120 ! ** and sums for s+, s- ( ref. 2, p. 1507 )
1125 sp ( j ) = ( 0.0, 0.0 )
1126 sm ( j ) = ( 0.0, 0.0 )
1132 sp ( j ) = ( 0.0, 0.0 )
1133 sm ( j ) = ( 0.0, 0.0 )
1134 sps( j ) = ( 0.0, 0.0 )
1135 sms( j ) = ( 0.0, 0.0 )
1138 ! ** initialize mie sums for efficiencies, etc.
1143 tforw( 1 ) = ( 0., 0. )
1144 tback( 1 ) = ( 0., 0. )
1147 ! --------- loop to sum mie series -----------------------------------
1151 ! ** compute various numerical coefficients
1156 coeff = twonp1 / ( fn * ( n + 1 ) )
1157 tcoef = twonp1 * ( fn * ( n + 1 ) )
1159 ! ** calculate mie series coefficients
1161 ! ** totally-reflecting case
1163 an = ( ( fn*xinv ) * psin - psinm1 ) / &
1164 ( ( fn*xinv ) * zetn - zetnm1 )
1167 else if ( noabs ) then
1168 ! ** no-absorption case
1170 an = ( ( rioriv*rbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1171 / ( ( rioriv*rbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1172 bn = ( ( mre * rbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1173 / ( ( mre * rbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1175 ! ** absorptive case
1177 an = ( ( cioriv * cbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1178 /( ( cioriv * cbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1179 bn = ( ( cior * cbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1180 /( ( cior * cbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1181 qsca = qsca + twonp1 * ( sq( an ) + sq( bn ) )
1184 ! ** save mie coefficients for *pmom* calculation
1187 ! ** increment mie sums for non-angle-
1188 ! ** dependent quantities
1190 sforw = sforw + twonp1 * ( an + bn )
1191 tforw( 1 ) = tforw( 1 ) + tcoef * ( an - bn )
1192 sback = sback + ( mm * twonp1 ) * ( an - bn )
1193 tback( 1 ) = tback( 1 ) + ( mm * tcoef ) * ( an + bn )
1194 gqsc = gqsc + ( fn - rn ) * dble( anm1 * dconjg( an ) &
1195 + bnm1 * dconjg( bn ) ) &
1196 + coeff * dble( an * dconjg( bn ) )
1199 ! ** put mie coefficients in form
1200 ! ** needed for computing s+, s-
1201 ! ** ( ref. 2, p. 1507 )
1202 anp = coeff * ( an + bn )
1203 bnp = coeff * ( an - bn )
1204 ! ** increment mie sums for s+, s-
1205 ! ** while upward recursing
1206 ! ** angular functions little pi
1209 ! ** arbitrary angles
1211 ! ** vectorizable loop
1213 rtmp = ( xmu( j ) * pin( j ) ) - pinm1( j )
1214 taun = fn * rtmp - pinm1( j )
1215 sp( j ) = sp( j ) + anp * ( pin( j ) + taun )
1216 sm( j ) = sm( j ) + bnp * ( pin( j ) - taun )
1217 pinm1( j ) = pin( j )
1218 pin( j ) = ( xmu( j ) * pin( j ) ) + np1dn * rtmp
1222 ! ** angles symmetric about 90 degrees
1225 ! ** vectorizable loop
1227 rtmp = ( xmu( j ) * pin( j ) ) - pinm1( j )
1228 taun = fn * rtmp - pinm1( j )
1229 sp ( j ) = sp ( j ) + anp * ( pin( j ) + taun )
1230 sms( j ) = sms( j ) + bnpm * ( pin( j ) + taun )
1231 sm ( j ) = sm ( j ) + bnp * ( pin( j ) - taun )
1232 sps( j ) = sps( j ) + anpm * ( pin( j ) - taun )
1233 pinm1( j ) = pin( j )
1234 pin( j ) = ( xmu( j ) * pin( j ) ) + np1dn * rtmp
1239 ! ** update relevant quantities for next
1240 ! ** pass through loop
1244 ! ** upward recurrence for ricatti-bessel
1245 ! ** functions ( ref. 1, eq. 17 )
1247 zet = ( twonp1 * xinv ) * zetn - zetnm1
1254 ! ---------- end loop to sum mie series --------------------------------
1257 qext = 2. / xx**2 * dble( sforw )
1258 if ( perfct .or. noabs ) then
1261 qsca = 2. / xx**2 * qsca
1264 gqsc = 4. / xx**2 * gqsc
1267 tforw( 2 ) = 0.5 * ( sforw + 0.25 * tforw( 1 ) )
1268 tforw( 1 ) = 0.5 * ( sforw - 0.25 * tforw( 1 ) )
1269 tback( 2 ) = 0.5 * ( sback + 0.25 * tback( 1 ) )
1270 tback( 1 ) = 0.5 * ( - sback + 0.25 * tback( 1 ) )
1273 ! ** recover scattering amplitudes
1274 ! ** from s+, s- ( ref. 1, eq. 11 )
1276 ! ** vectorizable loop
1277 do 110 j = 1, numang
1278 s1( j ) = 0.5 * ( sp( j ) + sm( j ) )
1279 s2( j ) = 0.5 * ( sp( j ) - sm( j ) )
1283 ! ** vectorizable loop
1284 do 120 j = 1, nangd2
1285 s1( j ) = 0.5 * ( sp( j ) + sm( j ) )
1286 s2( j ) = 0.5 * ( sp( j ) - sm( j ) )
1288 ! ** vectorizable loop
1289 do 130 j = 1, nangd2
1290 s1( numang+1 - j ) = 0.5 * ( sps( j ) + sms( j ) )
1291 s2( numang+1 - j ) = 0.5 * ( sps( j ) - sms( j ) )
1296 ! ** calculate legendre moments
1297 200 if ( nmom.gt.0 ) &
1298 call lpcoef ( ntrm, nmom, ipolzn, momdim, calcmo, npquan, &
1301 if ( dimag(crefin) .gt. 0.0 ) then
1302 ! ** take complex conjugates
1303 ! ** of scattering amplitudes
1304 sforw = dconjg( sforw )
1305 sback = dconjg( sback )
1307 tforw( i ) = dconjg( tforw(i) )
1308 tback( i ) = dconjg( tback(i) )
1311 do 220 j = 1, numang
1312 s1( j ) = dconjg( s1(j) )
1313 s2( j ) = dconjg( s2(j) )
1319 ! ** compare test case results with
1320 ! ** correct answers and abort if bad
1322 call testmi ( qext, qsca, gqsc, sforw, sback, s1, s2, &
1323 tforw, tback, pmom, momdim, ok )
1324 if ( .not. ok ) then
1327 call miprnt( prnt, xx, perfct, crefin, numang, xmu, qext, &
1328 qsca, gqsc, nmom, ipolzn, momdim, calcmo, &
1329 pmom, sforw, sback, tforw, tback, s1, s2 )
1330 call errmsg( 'miev0 -- self-test failed', .true. )
1332 ! ** restore user input values
1347 if ( prnt(1) .or. prnt(2) ) &
1348 call miprnt( prnt, xx, perfct, crefin, numang, xmu, qext, &
1349 qsca, gqsc, nmom, ipolzn, momdim, calcmo, &
1350 pmom, sforw, sback, tforw, tback, s1, s2 )
1354 end subroutine miev0
1355 !****************************************************************************
1356 subroutine ckinmi( numang, maxang, xx, perfct, crefin, momdim, &
1357 nmom, ipolzn, anyang, xmu, calcmo, npquan )
1359 ! check for bad input to 'miev0' and calculate -calcmo,npquan-
1362 logical perfct, anyang, calcmo(*)
1363 integer numang, maxang, momdim, nmom, ipolzn, npquan
1373 if ( numang.gt.maxang ) then
1374 call errmsg( 'miev0--parameter maxang too small', .true. )
1377 if ( numang.lt.0 ) call wrtbad( 'numang', inperr )
1378 if ( xx.lt.0. ) call wrtbad( 'xx', inperr )
1379 if ( .not.perfct .and. dble(crefin).le.0. ) &
1380 call wrtbad( 'crefin', inperr )
1381 if ( momdim.lt.1 ) call wrtbad( 'momdim', inperr )
1383 if ( nmom.ne.0 ) then
1384 if ( nmom.lt.0 .or. nmom.gt.momdim ) call wrtbad('nmom',inperr)
1385 if ( iabs(ipolzn).gt.4444 ) call wrtbad( 'ipolzn', inperr )
1388 calcmo( l ) = .false.
1390 if ( ipolzn.ne.0 ) then
1391 ! ** parse out -ipolzn- into its digits
1392 ! ** to find which phase quantities are
1393 ! ** to have their moments calculated
1395 write( string, '(i4)' ) iabs(ipolzn)
1397 ip = ichar( string(j:j) ) - ichar( '0' )
1398 if ( ip.ge.1 .and. ip.le.4 ) calcmo( ip ) = .true.
1399 if ( ip.eq.0 .or. (ip.ge.5 .and. ip.le.9) ) &
1400 call wrtbad( 'ipolzn', inperr )
1401 npquan = max0( npquan, ip )
1407 ! ** allow for slight imperfections in
1408 ! ** computation of cosine
1410 if ( xmu(i).lt.-1.00001 .or. xmu(i).gt.1.00001 ) &
1411 call wrtbad( 'xmu', inperr )
1414 do 22 i = 1, ( numang + 1 ) / 2
1415 if ( xmu(i).lt.-0.00001 .or. xmu(i).gt.1.00001 ) &
1416 call wrtbad( 'xmu', inperr )
1421 call errmsg( 'miev0--input error(s). aborting...', .true. )
1423 if ( xx.gt.20000.0 .or. dble(crefin).gt.10.0 .or. &
1424 dabs( dimag(crefin) ).gt.10.0 ) call errmsg( &
1425 'miev0--xx or crefin outside tested range', .false. )
1428 end subroutine ckinmi
1429 !***********************************************************************
1430 subroutine lpcoef ( ntrm, nmom, ipolzn, momdim, calcmo, npquan, &
1433 ! calculate legendre polynomial expansion coefficients (also
1434 ! called moments) for phase quantities ( ref. 5 formulation )
1436 ! input: ntrm number terms in mie series
1437 ! nmom, ipolzn, momdim 'miev0' arguments
1438 ! calcmo flags calculated from -ipolzn-
1439 ! npquan defined in 'miev0'
1440 ! a, b mie series coefficients
1442 ! output: pmom legendre moments ('miev0' argument)
1446 ! (1) eqs. 2-5 are in error in dave, appl. opt. 9,
1447 ! 1888 (1970). eq. 2 refers to m1, not m2; eq. 3 refers to
1448 ! m2, not m1. in eqs. 4 and 5, the subscripts on the second
1449 ! term in square brackets should be interchanged.
1451 ! (2) the general-case logic in this subroutine works correctly
1452 ! in the two-term mie series case, but subroutine 'lpco2t'
1453 ! is called instead, for speed.
1455 ! (3) subroutine 'lpco1t', to do the one-term case, is never
1456 ! called within the context of 'miev0', but is included for
1457 ! complete generality.
1459 ! (4) some improvement in speed is obtainable by combining the
1460 ! 310- and 410-loops, if moments for both the third and fourth
1461 ! phase quantities are desired, because the third phase quantity
1462 ! is the real part of a complex series, while the fourth phase
1463 ! quantity is the imaginary part of that very same series. but
1464 ! most users are not interested in the fourth phase quantity,
1465 ! which is related to circular polarization, so the present
1466 ! scheme is usually more efficient.
1470 integer ipolzn, momdim, nmom, ntrm, npquan
1471 real*8 pmom( 0:momdim, * )
1472 complex*16 a(*), b(*)
1474 ! ** specification of local variables
1476 ! am(m) numerical coefficients a-sub-m-super-l
1477 ! in dave, eqs. 1-15, as simplified in ref. 5.
1479 ! bi(i) numerical coefficients b-sub-i-super-l
1480 ! in dave, eqs. 1-15, as simplified in ref. 5.
1482 ! bidel(i) 1/2 bi(i) times factor capital-del in dave
1484 ! cm,dm() arrays c and d in dave, eqs. 16-17 (mueller form),
1485 ! calculated using recurrence derived in ref. 5
1487 ! cs,ds() arrays c and d in ref. 4, eqs. a5-a6 (sekera form),
1488 ! calculated using recurrence derived in ref. 5
1490 ! c,d() either -cm,dm- or -cs,ds-, depending on -ipolzn-
1492 ! evenl true for even-numbered moments; false otherwise
1494 ! idel 1 + little-del in dave
1496 ! maxtrm max. no. of terms in mie series
1498 ! maxmom max. no. of non-zero moments
1500 ! nummom number of non-zero moments
1504 integer maxtrm,maxmom,mxmom2,maxrcp
1505 parameter ( maxtrm = 1102, maxmom = 2*maxtrm, mxmom2 = maxmom/2, &
1506 maxrcp = 4*maxtrm + 2 )
1507 real*8 am( 0:maxtrm ), bi( 0:mxmom2 ), bidel( 0:mxmom2 ), &
1509 complex*16 cm( maxtrm ), dm( maxtrm ), cs( maxtrm ), ds( maxtrm ), &
1510 c( maxtrm ), d( maxtrm )
1511 integer k,j,l,nummom,ld2,idel,m,i,mmax,imax
1513 equivalence ( c, cm ), ( d, dm )
1514 logical pass1, evenl
1516 data pass1 / .true. /
1522 recip( k ) = 1.0 / k
1528 do 5 j = 1, max0( 1, npquan )
1533 if ( ntrm.eq.1 ) then
1534 call lpco1t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1536 else if ( ntrm.eq.2 ) then
1537 call lpco2t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1541 if ( ntrm+2 .gt. maxtrm ) &
1542 call errmsg( 'lpcoef--parameter maxtrm too small', .true. )
1544 ! ** calculate mueller c, d arrays
1545 cm( ntrm+2 ) = ( 0., 0. )
1546 dm( ntrm+2 ) = ( 0., 0. )
1547 cm( ntrm+1 ) = ( 1. - recip( ntrm+1 ) ) * b( ntrm )
1548 dm( ntrm+1 ) = ( 1. - recip( ntrm+1 ) ) * a( ntrm )
1549 cm( ntrm ) = ( recip(ntrm) + recip(ntrm+1) ) * a( ntrm ) &
1550 + ( 1. - recip(ntrm) ) * b( ntrm-1 )
1551 dm( ntrm ) = ( recip(ntrm) + recip(ntrm+1) ) * b( ntrm ) &
1552 + ( 1. - recip(ntrm) ) * a( ntrm-1 )
1554 do 10 k = ntrm-1, 2, -1
1555 cm( k ) = cm( k+2 ) - ( 1. + recip(k+1) ) * b( k+1 ) &
1556 + ( recip(k) + recip(k+1) ) * a( k ) &
1557 + ( 1. - recip(k) ) * b( k-1 )
1558 dm( k ) = dm( k+2 ) - ( 1. + recip(k+1) ) * a( k+1 ) &
1559 + ( recip(k) + recip(k+1) ) * b( k ) &
1560 + ( 1. - recip(k) ) * a( k-1 )
1562 cm( 1 ) = cm( 3 ) + 1.5 * ( a( 1 ) - b( 2 ) )
1563 dm( 1 ) = dm( 3 ) + 1.5 * ( b( 1 ) - a( 2 ) )
1565 if ( ipolzn.ge.0 ) then
1567 do 20 k = 1, ntrm + 2
1568 c( k ) = ( 2*k - 1 ) * cm( k )
1569 d( k ) = ( 2*k - 1 ) * dm( k )
1573 ! ** compute sekera c and d arrays
1574 cs( ntrm+2 ) = ( 0., 0. )
1575 ds( ntrm+2 ) = ( 0., 0. )
1576 cs( ntrm+1 ) = ( 0., 0. )
1577 ds( ntrm+1 ) = ( 0., 0. )
1579 do 30 k = ntrm, 1, -1
1580 cs( k ) = cs( k+2 ) + ( 2*k + 1 ) * ( cm( k+1 ) - b( k ) )
1581 ds( k ) = ds( k+2 ) + ( 2*k + 1 ) * ( dm( k+1 ) - a( k ) )
1584 do 40 k = 1, ntrm + 2
1585 c( k ) = ( 2*k - 1 ) * cs( k )
1586 d( k ) = ( 2*k - 1 ) * ds( k )
1592 if( ipolzn.lt.0 ) nummom = min0( nmom, 2*ntrm - 2 )
1593 if( ipolzn.ge.0 ) nummom = min0( nmom, 2*ntrm )
1594 if ( nummom .gt. maxmom ) &
1595 call errmsg( 'lpcoef--parameter maxtrm too small', .true. )
1597 ! ** loop over moments
1598 do 500 l = 0, nummom
1600 evenl = mod( l,2 ) .eq. 0
1601 ! ** calculate numerical coefficients
1602 ! ** a-sub-m and b-sub-i in dave
1603 ! ** double-sums for moments
1608 am( m ) = 2.0 * recip( 2*m + 1 )
1612 else if( evenl ) then
1616 am( m ) = ( 1. + recip( 2*m-l+1 ) ) * am( m )
1619 bi( i ) = ( 1. - recip( l-2*i ) ) * bi( i )
1621 bi( ld2 ) = ( 2. - recip( l ) ) * bi( ld2-1 )
1627 am( m ) = ( 1. - recip( 2*m+l+2 ) ) * am( m )
1630 bi( i ) = ( 1. - recip( l+2*i+1 ) ) * bi( i )
1634 ! ** establish upper limits for sums
1635 ! ** and incorporate factor capital-
1636 ! ** del into b-sub-i
1638 if( ipolzn.ge.0 ) mmax = mmax + 1
1639 imax = min0( ld2, mmax - ld2 )
1640 if( imax.lt.0 ) go to 600
1642 bidel( i ) = bi( i )
1644 if( evenl ) bidel( 0 ) = 0.5 * bidel( 0 )
1646 ! ** perform double sums just for
1647 ! ** phase quantities desired by user
1648 if( ipolzn.eq.0 ) then
1651 ! ** vectorizable loop (cray)
1653 do 100 m = ld2, mmax - i
1654 thesum = thesum + am( m ) * &
1655 ( dble( c(m-i+1) * dconjg( c(m+i+idel) ) ) &
1656 + dble( d(m-i+1) * dconjg( d(m+i+idel) ) ) )
1658 pmom( l,1 ) = pmom( l,1 ) + bidel( i ) * thesum
1660 pmom( l,1 ) = 0.5 * pmom( l,1 )
1665 if ( calcmo(1) ) then
1667 ! ** vectorizable loop (cray)
1669 do 150 m = ld2, mmax - i
1670 thesum = thesum + am( m ) * &
1671 dble( c(m-i+1) * dconjg( c(m+i+idel) ) )
1673 pmom( l,1 ) = pmom( l,1 ) + bidel( i ) * thesum
1678 if ( calcmo(2) ) then
1680 ! ** vectorizable loop (cray)
1682 do 200 m = ld2, mmax - i
1683 thesum = thesum + am( m ) * &
1684 dble( d(m-i+1) * dconjg( d(m+i+idel) ) )
1686 pmom( l,2 ) = pmom( l,2 ) + bidel( i ) * thesum
1691 if ( calcmo(3) ) then
1693 ! ** vectorizable loop (cray)
1695 do 300 m = ld2, mmax - i
1696 thesum = thesum + am( m ) * &
1697 ( dble( c(m-i+1) * dconjg( d(m+i+idel) ) ) &
1698 + dble( c(m+i+idel) * dconjg( d(m-i+1) ) ) )
1700 pmom( l,3 ) = pmom( l,3 ) + bidel( i ) * thesum
1702 pmom( l,3 ) = 0.5 * pmom( l,3 )
1706 if ( calcmo(4) ) then
1708 ! ** vectorizable loop (cray)
1710 do 400 m = ld2, mmax - i
1711 thesum = thesum + am( m ) * &
1712 ( dimag( c(m-i+1) * dconjg( d(m+i+idel) ) ) &
1713 + dimag( c(m+i+idel) * dconjg( d(m-i+1) ) ))
1715 pmom( l,4 ) = pmom( l,4 ) + bidel( i ) * thesum
1717 pmom( l,4 ) = - 0.5 * pmom( l,4 )
1724 end subroutine lpcoef
1725 !*********************************************************************
1726 subroutine lpco1t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1728 ! calculate legendre polynomial expansion coefficients (also
1729 ! called moments) for phase quantities in special case where
1730 ! no. terms in mie series = 1
1732 ! input: nmom, ipolzn, momdim 'miev0' arguments
1733 ! calcmo flags calculated from -ipolzn-
1734 ! a(1), b(1) mie series coefficients
1736 ! output: pmom legendre moments
1740 integer ipolzn, momdim, nmom,nummom,l
1741 real*8 pmom( 0:momdim, * ),sq,a1sq,b1sq
1742 complex*16 a(*), b(*), ctmp, a1b1c
1743 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
1748 a1b1c = a(1) * dconjg( b(1) )
1750 if( ipolzn.lt.0 ) then
1752 if( calcmo(1) ) pmom( 0,1 ) = 2.25 * b1sq
1753 if( calcmo(2) ) pmom( 0,2 ) = 2.25 * a1sq
1754 if( calcmo(3) ) pmom( 0,3 ) = 2.25 * dble( a1b1c )
1755 if( calcmo(4) ) pmom( 0,4 ) = 2.25 *dimag( a1b1c )
1759 nummom = min0( nmom, 2 )
1760 ! ** loop over moments
1761 do 100 l = 0, nummom
1763 if( ipolzn.eq.0 ) then
1764 if( l.eq.0 ) pmom( l,1 ) = 1.5 * ( a1sq + b1sq )
1765 if( l.eq.1 ) pmom( l,1 ) = 1.5 * dble( a1b1c )
1766 if( l.eq.2 ) pmom( l,1 ) = 0.15 * ( a1sq + b1sq )
1770 if( calcmo(1) ) then
1771 if( l.eq.0 ) pmom( l,1 ) = 2.25 * ( a1sq + b1sq / 3. )
1772 if( l.eq.1 ) pmom( l,1 ) = 1.5 * dble( a1b1c )
1773 if( l.eq.2 ) pmom( l,1 ) = 0.3 * b1sq
1776 if( calcmo(2) ) then
1777 if( l.eq.0 ) pmom( l,2 ) = 2.25 * ( b1sq + a1sq / 3. )
1778 if( l.eq.1 ) pmom( l,2 ) = 1.5 * dble( a1b1c )
1779 if( l.eq.2 ) pmom( l,2 ) = 0.3 * a1sq
1782 if( calcmo(3) ) then
1783 if( l.eq.0 ) pmom( l,3 ) = 3.0 * dble( a1b1c )
1784 if( l.eq.1 ) pmom( l,3 ) = 0.75 * ( a1sq + b1sq )
1785 if( l.eq.2 ) pmom( l,3 ) = 0.3 * dble( a1b1c )
1788 if( calcmo(4) ) then
1789 if( l.eq.0 ) pmom( l,4 ) = - 1.5 * dimag( a1b1c )
1790 if( l.eq.1 ) pmom( l,4 ) = 0.0
1791 if( l.eq.2 ) pmom( l,4 ) = 0.3 * dimag( a1b1c )
1799 end subroutine lpco1t
1800 !********************************************************************
1801 subroutine lpco2t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1803 ! calculate legendre polynomial expansion coefficients (also
1804 ! called moments) for phase quantities in special case where
1805 ! no. terms in mie series = 2
1807 ! input: nmom, ipolzn, momdim 'miev0' arguments
1808 ! calcmo flags calculated from -ipolzn-
1809 ! a(1-2), b(1-2) mie series coefficients
1811 ! output: pmom legendre moments
1815 integer ipolzn, momdim, nmom,l,nummom
1816 real*8 pmom( 0:momdim, * ),sq,pm1,pm2,a2sq,b2sq
1817 complex*16 a(*), b(*)
1818 complex*16 a2c, b2c, ctmp, ca, cac, cat, cb, cbc, cbt, cg, ch
1819 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
1822 ca = 3. * a(1) - 5. * b(2)
1823 cat= 3. * b(1) - 5. * a(2)
1827 a2c = dconjg( a(2) )
1828 b2c = dconjg( b(2) )
1830 if( ipolzn.lt.0 ) then
1831 ! ** loop over sekera moments
1832 nummom = min0( nmom, 2 )
1835 if( calcmo(1) ) then
1836 if( l.eq.0 ) pmom( l,1 ) = 0.25 * ( sq(cat) + &
1838 if( l.eq.1 ) pmom( l,1 ) = (5./3.) * dble( cat * b2c )
1839 if( l.eq.2 ) pmom( l,1 ) = (10./3.) * b2sq
1842 if( calcmo(2) ) then
1843 if( l.eq.0 ) pmom( l,2 ) = 0.25 * ( sq(ca) + &
1845 if( l.eq.1 ) pmom( l,2 ) = (5./3.) * dble( ca * a2c )
1846 if( l.eq.2 ) pmom( l,2 ) = (10./3.) * a2sq
1849 if( calcmo(3) ) then
1850 if( l.eq.0 ) pmom( l,3 ) = 0.25 * dble( cat*cac + &
1851 (100./3.)*b(2)*a2c )
1852 if( l.eq.1 ) pmom( l,3 ) = 5./6. * dble( b(2)*cac + &
1854 if( l.eq.2 ) pmom( l,3 ) = 10./3. * dble( b(2) * a2c )
1857 if( calcmo(4) ) then
1858 if( l.eq.0 ) pmom( l,4 ) = -0.25 * dimag( cat*cac + &
1859 (100./3.)*b(2)*a2c )
1860 if( l.eq.1 ) pmom( l,4 ) = -5./6. * dimag( b(2)*cac + &
1862 if( l.eq.2 ) pmom( l,4 ) = -10./3. * dimag( b(2) * a2c )
1869 cb = 3. * b(1) + 5. * a(2)
1870 cbt= 3. * a(1) + 5. * b(2)
1872 cg = ( cbc*cbt + 10.*( cac*a(2) + b2c*cat) ) / 3.
1873 ch = 2.*( cbc*a(2) + b2c*cbt )
1875 ! ** loop over mueller moments
1876 nummom = min0( nmom, 4 )
1877 do 100 l = 0, nummom
1879 if( ipolzn.eq.0 .or. calcmo(1) ) then
1880 if( l.eq.0 ) pm1 = 0.25 * sq(ca) + sq(cb) / 12. &
1881 + (5./3.) * dble(ca*b2c) + 5.*b2sq
1882 if( l.eq.1 ) pm1 = dble( cb * ( cac/6. + b2c ) )
1883 if( l.eq.2 ) pm1 = sq(cb)/30. + (20./7.) * b2sq &
1884 + (2./3.) * dble( ca * b2c )
1885 if( l.eq.3 ) pm1 = (2./7.) * dble( cb * b2c )
1886 if( l.eq.4 ) pm1 = (40./63.) * b2sq
1887 if ( calcmo(1) ) pmom( l,1 ) = pm1
1890 if( ipolzn.eq.0 .or. calcmo(2) ) then
1891 if( l.eq.0 ) pm2 = 0.25*sq(cat) + sq(cbt) / 12. &
1892 + (5./3.) * dble(cat*a2c) + 5.*a2sq
1893 if( l.eq.1 ) pm2 = dble( cbt * ( dconjg(cat)/6. + a2c) )
1894 if( l.eq.2 ) pm2 = sq(cbt)/30. + (20./7.) * a2sq &
1895 + (2./3.) * dble( cat * a2c )
1896 if( l.eq.3 ) pm2 = (2./7.) * dble( cbt * a2c )
1897 if( l.eq.4 ) pm2 = (40./63.) * a2sq
1898 if ( calcmo(2) ) pmom( l,2 ) = pm2
1901 if( ipolzn.eq.0 ) then
1902 pmom( l,1 ) = 0.5 * ( pm1 + pm2 )
1906 if( calcmo(3) ) then
1907 if( l.eq.0 ) pmom( l,3 ) = 0.25 * dble( cac*cat + cg + &
1909 if( l.eq.1 ) pmom( l,3 ) = dble( cac*cbt + cbc*cat + &
1911 if( l.eq.2 ) pmom( l,3 ) = 0.1 * dble( cg + (200./7.) * &
1913 if( l.eq.3 ) pmom( l,3 ) = dble( ch ) / 14.
1914 if( l.eq.4 ) pmom( l,3 ) = 40./63. * dble( b2c * a(2) )
1917 if( calcmo(4) ) then
1918 if( l.eq.0 ) pmom( l,4 ) = 0.25 * dimag( cac*cat + cg + &
1920 if( l.eq.1 ) pmom( l,4 ) = dimag( cac*cbt + cbc*cat + &
1922 if( l.eq.2 ) pmom( l,4 ) = 0.1 * dimag( cg + (200./7.) * &
1924 if( l.eq.3 ) pmom( l,4 ) = dimag( ch ) / 14.
1925 if( l.eq.4 ) pmom( l,4 ) = 40./63. * dimag( b2c * a(2) )
1933 end subroutine lpco2t
1934 !*********************************************************************
1935 subroutine biga( cior, xx, ntrm, noabs, yesang, rbiga, cbiga )
1937 ! calculate logarithmic derivatives of j-bessel-function
1939 ! input : cior, xx, ntrm, noabs, yesang (defined in 'miev0')
1941 ! output : rbiga or cbiga (defined in 'miev0')
1943 ! internal variables :
1945 ! confra value of lentz continued fraction for -cbiga(ntrm)-,
1946 ! used to initialize downward recurrence.
1947 ! down = true, use down-recurrence. false, do not.
1948 ! f1,f2,f3 arithmetic statement functions used in determining
1949 ! whether to use up- or down-recurrence
1950 ! ( ref. 2, eqs. 6-8 )
1951 ! mre real refractive index
1952 ! mim imaginary refractive index
1953 ! rezinv 1 / ( mre * xx ); temporary variable for recurrence
1954 ! zinv 1 / ( cior * xx ); temporary variable for recurrence
1957 logical down, noabs, yesang
1959 real*8 mre, mim, rbiga(*), xx, rezinv, rtmp, f1,f2,f3
1960 ! complex*16 cior, ctmp, confra, cbiga(*), zinv
1961 complex*16 cior, ctmp, cbiga(*), zinv
1962 f1( mre ) = - 8.0 + mre**2 * ( 26.22 + mre * ( - 0.4474 &
1963 + mre**3 * ( 0.00204 - 0.000175 * mre ) ) )
1964 f2( mre ) = 3.9 + mre * ( - 10.8 + 13.78 * mre )
1965 f3( mre ) = - 15.04 + mre * ( 8.42 + 16.35 * mre )
1967 ! ** decide whether 'biga' can be
1968 ! ** calculated by up-recurrence
1970 mim = dabs( dimag( cior ) )
1971 if ( mre.lt.1.0 .or. mre.gt.10.0 .or. mim.gt.10.0 ) then
1973 else if ( yesang ) then
1975 if ( mim*xx .lt. f2( mre ) ) down = .false.
1978 if ( mim*xx .lt. f1( mre ) ) down = .false.
1981 zinv = 1.0 / ( cior * xx )
1982 rezinv = 1.0 / ( mre * xx )
1985 ! ** compute initial high-order 'biga' using
1986 ! ** lentz method ( ref. 1, pp. 17-20 )
1988 ctmp = confra( ntrm, zinv, xx )
1990 ! *** downward recurrence for 'biga'
1991 ! *** ( ref. 1, eq. 22 )
1993 ! ** no-absorption case
1994 rbiga( ntrm ) = dble( ctmp )
1995 do 25 n = ntrm, 2, - 1
1996 rbiga( n-1 ) = (n*rezinv) &
1997 - 1.0 / ( (n*rezinv) + rbiga( n ) )
2001 ! ** absorptive case
2002 cbiga( ntrm ) = ctmp
2003 do 30 n = ntrm, 2, - 1
2004 cbiga( n-1 ) = (n*zinv) - 1.0 / ( (n*zinv) + cbiga( n ) )
2010 ! *** upward recurrence for 'biga'
2011 ! *** ( ref. 1, eqs. 20-21 )
2013 ! ** no-absorption case
2014 rtmp = dsin( mre*xx )
2015 rbiga( 1 ) = - rezinv &
2016 + rtmp / ( rtmp*rezinv - dcos( mre*xx ) )
2018 rbiga( n ) = - ( n*rezinv ) &
2019 + 1.0 / ( ( n*rezinv ) - rbiga( n-1 ) )
2023 ! ** absorptive case
2024 ctmp = cdexp( - dcmplx(0.d0,2.d0) * cior * xx )
2025 cbiga( 1 ) = - zinv + (1.-ctmp) / ( zinv * (1.-ctmp) - &
2026 dcmplx(0.d0,1.d0)*(1.+ctmp) )
2028 cbiga( n ) = - (n*zinv) + 1.0 / ((n*zinv) - cbiga( n-1 ))
2036 !**********************************************************************
2037 complex*16 function confra( n, zinv, xx )
2039 ! compute bessel function ratio capital-a-sub-n from its
2040 ! continued fraction using lentz method ( ref. 1, pp. 17-20 )
2042 ! zinv = reciprocal of argument of capital-a
2044 ! i n t e r n a l v a r i a b l e s
2045 ! ------------------------------------
2047 ! cak term in continued fraction expansion of capital-a
2048 ! ( ref. 1, eq. 25 )
2049 ! capt factor used in lentz iteration for capital-a
2050 ! ( ref. 1, eq. 27 )
2051 ! cdenom denominator in -capt- ( ref. 1, eq. 28b )
2052 ! cnumer numerator in -capt- ( ref. 1, eq. 28a )
2053 ! cdtd product of two successive denominators of -capt-
2054 ! factors ( ref. 1, eq. 34c )
2055 ! cntn product of two successive numerators of -capt-
2056 ! factors ( ref. 1, eq. 34b )
2057 ! eps1 ill-conditioning criterion
2058 ! eps2 convergence criterion
2059 ! kk subscript k of -cak- ( ref. 1, eq. 25b )
2060 ! kount iteration counter ( used only to prevent runaway )
2061 ! maxit max. allowed no. of iterations
2062 ! mm + 1 and - 1, alternately
2065 integer n,maxit,mm,kk,kount
2068 complex*16 cak, capt, cdenom, cdtd, cnumer, cntn
2069 ! data eps1 / 1.e - 2 /, eps2 / 1.e - 8 /
2070 data eps1 / 1.d-2 /, eps2 / 1.d-8 /
2071 data maxit / 10000 /
2073 ! *** ref. 1, eqs. 25a, 27
2074 confra = ( n + 1 ) * zinv
2077 cak = ( mm * kk ) * zinv
2079 cnumer = cdenom + 1.0 / confra
2082 20 kount = kount + 1
2083 if ( kount.gt.maxit ) &
2084 call errmsg( 'confra--iteration failed to converge$', .true.)
2086 ! *** ref. 2, eq. 25b
2089 cak = ( mm * kk ) * zinv
2090 ! *** ref. 2, eq. 32
2091 if ( cdabs( cnumer/cak ).le.eps1 &
2092 .or. cdabs( cdenom/cak ).le.eps1 ) then
2094 ! ** ill-conditioned case -- stride
2095 ! ** two terms instead of one
2097 ! *** ref. 2, eqs. 34
2098 cntn = cak * cnumer + 1.0
2099 cdtd = cak * cdenom + 1.0
2100 confra = ( cntn / cdtd ) * confra
2101 ! *** ref. 2, eq. 25b
2104 cak = ( mm * kk ) * zinv
2105 ! *** ref. 2, eqs. 35
2106 cnumer = cak + cnumer / cntn
2107 cdenom = cak + cdenom / cdtd
2112 ! ** well-conditioned case
2114 ! *** ref. 2, eqs. 26, 27
2115 capt = cnumer / cdenom
2116 confra = capt * confra
2117 ! ** check for convergence
2118 ! ** ( ref. 2, eq. 31 )
2120 if ( dabs( dble(capt) - 1.0 ).ge.eps2 &
2121 .or. dabs( dimag(capt) ) .ge.eps2 ) then
2123 ! *** ref. 2, eqs. 30a-b
2124 cnumer = cak + 1.0 / cnumer
2125 cdenom = cak + 1.0 / cdenom
2133 !********************************************************************
2134 subroutine miprnt( prnt, xx, perfct, crefin, numang, xmu, &
2135 qext, qsca, gqsc, nmom, ipolzn, momdim, &
2136 calcmo, pmom, sforw, sback, tforw, tback, &
2139 ! print scattering quantities of a single particle
2142 logical perfct, prnt(*), calcmo(*)
2143 integer ipolzn, momdim, nmom, numang,i,m,j
2144 real*8 gqsc, pmom( 0:momdim, * ), qext, qsca, xx, xmu(*)
2145 real*8 fi1,fi2,fnorm
2146 complex*16 crefin, sforw, sback, tforw(*), tback(*), s1(*), s2(*)
2150 if ( perfct ) write ( *, '(''1'',10x,a,1p,e11.4)' ) &
2151 'perfectly conducting case, size parameter =', xx
2152 if ( .not.perfct ) write ( *, '(''1'',10x,3(a,1p,e11.4))' ) &
2153 'refractive index: real ', dble(crefin), &
2154 ' imag ', dimag(crefin), ', size parameter =', xx
2156 if ( prnt(1) .and. numang.gt.0 ) then
2158 write ( *, '(/,a)' ) &
2159 ' cos(angle) ------- s1 --------- ------- s2 ---------'// &
2160 ' --- s1*conjg(s2) --- i1=s1**2 i2=s2**2 (i1+i2)/2'// &
2163 fi1 = dble( s1(i) ) **2 + dimag( s1(i) )**2
2164 fi2 = dble( s2(i) ) **2 + dimag( s2(i) )**2
2165 write( *, '( i4, f10.6, 1p,10e11.3 )' ) &
2166 i, xmu(i), s1(i), s2(i), s1(i)*dconjg(s2(i)), &
2167 fi1, fi2, 0.5*(fi1+fi2), (fi2-fi1)/(fi2+fi1)
2175 write ( *, '(/,a,9x,a,17x,a,17x,a,/,(0p,f7.2, 1p,6e12.3) )' ) &
2176 ' angle', 's-sub-1', 't-sub-1', 't-sub-2', &
2177 0.0, sforw, tforw(1), tforw(2), &
2178 180., sback, tback(1), tback(2)
2179 write ( *, '(/,4(a,1p,e11.4))' ) &
2180 ' efficiency factors, extinction:', qext, &
2181 ' scattering:', qsca, &
2182 ' absorption:', qext-qsca, &
2183 ' rad. pressure:', qext-gqsc
2185 if ( nmom.gt.0 ) then
2187 write( *, '(/,a)' ) ' normalized moments of :'
2188 if ( ipolzn.eq.0 ) write ( *, '(''+'',27x,a)' ) 'phase fcn'
2189 if ( ipolzn.gt.0 ) write ( *, '(''+'',33x,a)' ) &
2191 if ( ipolzn.lt.0 ) write ( *, '(''+'',33x,a)' ) &
2194 fnorm = 4. / ( xx**2 * qsca )
2196 write ( *, '(a,i4)' ) ' moment no.', m
2198 if( calcmo(j) ) then
2199 write( fmt, 98 ) 24 + (j-1)*13
2200 write ( *,fmt ) fnorm * pmom(m,j)
2209 98 format( '( ''+'', t', i2, ', 1p,e13.4 )' )
2210 end subroutine miprnt
2211 !**************************************************************************
2212 subroutine small1 ( xx, numang, xmu, qext, qsca, gqsc, sforw, &
2213 sback, s1, s2, tforw, tback, a, b )
2215 ! small-particle limit of mie quantities in totally reflecting
2216 ! limit ( mie series truncated after 2 terms )
2218 ! a,b first two mie coefficients, with numerator and
2219 ! denominator expanded in powers of -xx- ( a factor
2220 ! of xx**3 is missing but is restored before return
2221 ! to calling program ) ( ref. 2, p. 1508 )
2225 real*8 gqsc, qext, qsca, xx, xmu(*)
2226 real*8 twothr,fivthr,fivnin,sq,rtmp
2227 complex*16 a( 2 ), b( 2 ), sforw, sback, s1(*), s2(*), &
2230 parameter ( twothr = 2./3., fivthr = 5./3., fivnin = 5./9. )
2232 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
2235 a( 1 ) = dcmplx ( 0.d0, twothr * ( 1. - 0.2 * xx**2 ) ) &
2236 / dcmplx ( 1.d0 - 0.5 * xx**2, twothr * xx**3 )
2238 b( 1 ) = dcmplx ( 0.d0, - ( 1. - 0.1 * xx**2 ) / 3. ) &
2239 / dcmplx ( 1.d0 + 0.5 * xx**2, - xx**3 / 3. )
2241 a( 2 ) = dcmplx ( 0.d0, xx**2 / 30. )
2242 b( 2 ) = dcmplx ( 0.d0, - xx**2 / 45. )
2244 qsca = 6. * xx**4 * ( sq( a(1) ) + sq( b(1) ) &
2245 + fivthr * ( sq( a(2) ) + sq( b(2) ) ) )
2247 gqsc = 6. * xx**4 * dble( a(1) * dconjg( a(2) + b(1) ) &
2248 + ( b(1) + fivnin * a(2) ) * dconjg( b(2) ) )
2251 sforw = rtmp * ( a(1) + b(1) + fivthr * ( a(2) + b(2) ) )
2252 sback = rtmp * ( a(1) - b(1) - fivthr * ( a(2) - b(2) ) )
2253 tforw( 1 ) = rtmp * ( b(1) + fivthr * ( 2.*b(2) - a(2) ) )
2254 tforw( 2 ) = rtmp * ( a(1) + fivthr * ( 2.*a(2) - b(2) ) )
2255 tback( 1 ) = rtmp * ( b(1) - fivthr * ( 2.*b(2) + a(2) ) )
2256 tback( 2 ) = rtmp * ( a(1) - fivthr * ( 2.*a(2) + b(2) ) )
2259 s1( j ) = rtmp * ( a(1) + b(1) * xmu(j) + fivthr * &
2260 ( a(2) * xmu(j) + b(2) * ( 2.*xmu(j)**2 - 1. )) )
2261 s2( j ) = rtmp * ( b(1) + a(1) * xmu(j) + fivthr * &
2262 ( b(2) * xmu(j) + a(2) * ( 2.*xmu(j)**2 - 1. )) )
2264 ! ** recover actual mie coefficients
2265 a( 1 ) = xx**3 * a( 1 )
2266 a( 2 ) = xx**3 * a( 2 )
2267 b( 1 ) = xx**3 * b( 1 )
2268 b( 2 ) = xx**3 * b( 2 )
2271 end subroutine small1
2272 !*************************************************************************
2273 subroutine small2 ( xx, cior, calcqe, numang, xmu, qext, qsca, &
2274 gqsc, sforw, sback, s1, s2, tforw, tback, &
2277 ! small-particle limit of mie quantities for general refractive
2278 ! index ( mie series truncated after 2 terms )
2280 ! a,b first two mie coefficients, with numerator and
2281 ! denominator expanded in powers of -xx- ( a factor
2282 ! of xx**3 is missing but is restored before return
2283 ! to calling program ) ( ref. 2, p. 1508 )
2285 ! ciorsq square of refractive index
2290 real*8 gqsc, qext, qsca, xx, xmu(*)
2291 real*8 twothr,fivthr,sq,rtmp
2292 complex*16 a( 2 ), b( 2 ), cior, sforw, sback, s1(*), s2(*), &
2295 parameter ( twothr = 2./3., fivthr = 5./3. )
2296 complex*16 ctmp, ciorsq
2297 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
2301 ctmp = dcmplx( 0.d0, twothr ) * ( ciorsq - 1.0 )
2302 a(1) = ctmp * ( 1.0 - 0.1 * xx**2 + (ciorsq/350. + 1./280.)*xx**4) &
2303 / ( ciorsq + 2.0 + ( 1.0 - 0.7 * ciorsq ) * xx**2 &
2304 - ( ciorsq**2/175. - 0.275 * ciorsq + 0.25 ) * xx**4 &
2305 + xx**3 * ctmp * ( 1.0 - 0.1 * xx**2 ) )
2307 b(1) = (xx**2/30.) * ctmp * ( 1.0 + (ciorsq/35. - 1./14.) *xx**2 ) &
2308 / ( 1.0 - ( ciorsq/15. - 1./6. ) * xx**2 )
2310 a(2) = ( 0.1 * xx**2 ) * ctmp * ( 1.0 - xx**2 / 14. ) &
2311 / ( 2. * ciorsq + 3. - ( ciorsq/7. - 0.5 ) * xx**2 )
2313 qsca = 6. * xx**4 * ( sq(a(1)) + sq(b(1)) + fivthr * sq(a(2)) )
2314 gqsc = 6. * xx**4 * dble( a(1) * dconjg( a(2) + b(1) ) )
2316 if ( calcqe ) qext = 6. * xx * dble( a(1) + b(1) + fivthr * a(2) )
2319 sforw = rtmp * ( a(1) + b(1) + fivthr * a(2) )
2320 sback = rtmp * ( a(1) - b(1) - fivthr * a(2) )
2321 tforw( 1 ) = rtmp * ( b(1) - fivthr * a(2) )
2322 tforw( 2 ) = rtmp * ( a(1) + 2. * fivthr * a(2) )
2323 tback( 1 ) = tforw( 1 )
2324 tback( 2 ) = rtmp * ( a(1) - 2. * fivthr * a(2) )
2327 s1( j ) = rtmp * ( a(1) + ( b(1) + fivthr * a(2) ) * xmu(j) )
2328 s2( j ) = rtmp * ( b(1) + a(1) * xmu(j) + fivthr * a(2) &
2329 * ( 2. * xmu(j)**2 - 1. ) )
2331 ! ** recover actual mie coefficients
2332 a( 1 ) = xx**3 * a( 1 )
2333 a( 2 ) = xx**3 * a( 2 )
2334 b( 1 ) = xx**3 * b( 1 )
2338 end subroutine small2
2339 !***********************************************************************
2340 subroutine testmi ( qext, qsca, gqsc, sforw, sback, s1, s2, &
2341 tforw, tback, pmom, momdim, ok )
2343 ! compare mie code test case results with correct answers
2344 ! and return ok=false if even one result is inaccurate.
2346 ! the test case is : mie size parameter = 10
2347 ! refractive index = 1.5 - 0.1 i
2348 ! scattering angle = 140 degrees
2351 ! results for this case may be found among the test cases
2352 ! at the end of reference (1).
2354 ! *** note *** when running on some computers, esp. in single
2355 ! precision, the 'accur' criterion below may have to be relaxed.
2356 ! however, if 'accur' must be set larger than 10**-3 for some
2357 ! size parameters, your computer is probably not accurate
2358 ! enough to do mie computations for those size parameters.
2362 real*8 qext, qsca, gqsc, pmom( 0:momdim, * )
2363 complex*16 sforw, sback, s1(*), s2(*), tforw(*), tback(*)
2366 real*8 accur, testqe, testqs, testgq, testpm( 0:1 )
2367 complex*16 testsf, testsb,tests1,tests2,testtf(2), testtb(2)
2368 data testqe / 2.459791 /, testqs / 1.235144 /, &
2369 testgq / 1.139235 /, testsf / ( 61.49476, -3.177994 ) /, &
2370 testsb / ( 1.493434, 0.2963657 ) /, &
2371 tests1 / ( -0.1548380, -1.128972) /, &
2372 tests2 / ( 0.05669755, 0.5425681) /, &
2373 testtf / ( 12.95238, -136.6436 ), ( 48.54238, 133.4656 ) /, &
2374 testtb / ( 41.88414, -15.57833 ), ( 43.37758, -15.28196 )/, &
2375 testpm / 227.1975, 183.6898 /
2377 ! data accur / 1.e-5 /
2378 data accur / 1.e-4 /
2379 wrong( calc, exact ) = dabs( (calc - exact) / exact ) .gt. accur
2383 if ( wrong( qext,testqe ) ) &
2384 call tstbad( 'qext', abs((qext - testqe) / testqe), ok )
2385 if ( wrong( qsca,testqs ) ) &
2386 call tstbad( 'qsca', abs((qsca - testqs) / testqs), ok )
2387 if ( wrong( gqsc,testgq ) ) &
2388 call tstbad( 'gqsc', abs((gqsc - testgq) / testgq), ok )
2390 if ( wrong( dble(sforw), dble(testsf) ) .or. &
2391 wrong( dimag(sforw), dimag(testsf) ) ) &
2392 call tstbad( 'sforw', cdabs((sforw - testsf) / testsf), ok )
2394 if ( wrong( dble(sback), dble(testsb) ) .or. &
2395 wrong( dimag(sback), dimag(testsb) ) ) &
2396 call tstbad( 'sback', cdabs((sback - testsb) / testsb), ok )
2398 if ( wrong( dble(s1(1)), dble(tests1) ) .or. &
2399 wrong( dimag(s1(1)), dimag(tests1) ) ) &
2400 call tstbad( 's1', cdabs((s1(1) - tests1) / tests1), ok )
2402 if ( wrong( dble(s2(1)), dble(tests2) ) .or. &
2403 wrong( dimag(s2(1)), dimag(tests2) ) ) &
2404 call tstbad( 's2', cdabs((s2(1) - tests2) / tests2), ok )
2407 if ( wrong( dble(tforw(n)), dble(testtf(n)) ) .or. &
2408 wrong( dimag(tforw(n)), dimag(testtf(n)) ) ) &
2409 call tstbad( 'tforw', cdabs( (tforw(n) - testtf(n)) / &
2411 if ( wrong( dble(tback(n)), dble(testtb(n)) ) .or. &
2412 wrong( dimag(tback(n)), dimag(testtb(n)) ) ) &
2413 call tstbad( 'tback', cdabs( (tback(n) - testtb(n)) / &
2418 if ( wrong( pmom(m,1), testpm(m) ) ) &
2419 call tstbad( 'pmom', dabs( (pmom(m,1)-testpm(m)) / &
2425 end subroutine testmi
2426 !**************************************************************************
2427 subroutine errmsg( messag, fatal )
2429 ! print out a warning or error message; abort if error
2431 USE module_peg_util, only: peg_message, peg_error_fatal
2436 character*(*) messag
2437 integer maxmsg, nummsg
2438 save maxmsg, nummsg, once
2439 data nummsg / 0 /, maxmsg / 100 /, once / .false. /
2443 ! write ( *, '(2a)' ) ' ******* error >>>>>> ', messag
2445 write( msg, '(a)' ) &
2446 'FASTJ mie fatal error ' // &
2448 call peg_message( lunerr, msg )
2449 call peg_error_fatal( lunerr, msg )
2453 if ( nummsg.gt.maxmsg ) then
2454 ! if ( .not.once ) write ( *,99 )
2455 if ( .not.once )then
2456 write( msg, '(a)' ) &
2457 'FASTJ mie: too many warning messages -- no longer printing '
2458 call peg_message( lunerr, msg )
2462 msg = 'FASTJ mie warning ' // messag
2463 call peg_message( lunerr, msg )
2464 ! write ( *, '(2a)' ) ' ******* warning >>>>>> ', messag
2469 ! 99 format( ///,' >>>>>> too many warning messages -- ', &
2470 ! 'they will no longer be printed <<<<<<<', /// )
2471 end subroutine errmsg
2472 !********************************************************************
2473 subroutine wrtbad ( varnam, erflag )
2475 ! write names of erroneous variables
2477 ! input : varnam = name of erroneous variable to be written
2478 ! ( character, any length )
2480 ! output : erflag = logical flag, set true by this routine
2481 ! ----------------------------------------------------------------------
2482 USE module_peg_util, only: peg_message
2485 character*(*) varnam
2487 integer maxmsg, nummsg
2490 data nummsg / 0 /, maxmsg / 50 /
2494 ! write ( *, '(3a)' ) ' **** input variable ', varnam, &
2496 msg = 'FASTJ mie input variable in error ' // varnam
2497 call peg_message( lunerr, msg )
2499 if ( nummsg.eq.maxmsg ) &
2500 call errmsg ( 'too many input variable errors. aborting...$', .true. )
2503 end subroutine wrtbad
2504 !******************************************************************
2505 subroutine tstbad( varnam, relerr, ok )
2507 ! write name (-varnam-) of variable failing self-test and its
2508 ! percent error from the correct value. return ok = false.
2511 character*(*) varnam
2517 write( *, '(/,3a,1p,e11.2,a)' ) &
2518 ' output variable ', varnam,' differed by', 100.*relerr, &
2519 ' per cent from correct value. self-test failed.'
2522 end subroutine tstbad
2523 !-----------------------------------------------------------------------
2524 end module module_fastj_mie