1 !**********************************************************************************
2 ! This computer software was prepared by Battelle Memorial Institute, hereinafter
3 ! the Contractor, under Contract No. DE-AC05-76RL0 1830 with the Department of
4 ! Energy (DOE). NEITHER THE GOVERNMENT NOR THE CONTRACTOR MAKES ANY WARRANTY,
5 ! EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE.
7 ! Module to Compute Aerosol Optical Properties
8 ! * Primary investigator: James C. Barnard
9 ! * Co-investigators: Rahul A. Zaveri, Richard C. Easter, William I. Gustafson Jr.
10 ! Last update: September 2005
15 ! Pacific Northwest National Laboratory
16 ! P.O. Box 999, MSIN K9-30
18 ! Phone: (509) 372-6116
19 ! Email: Jerome.Fast@pnl.gov
21 ! Please report any bugs or problems to Jerome Fast, the WRF-chem implmentation
22 ! team leader for PNNL
25 ! 1) This module may not be included in commerical package or used for any
26 ! commercial applications without the consent of the PNNL contact.
27 ! 2) This module is provided to the WRF modeling community; however, no portion
28 ! of it can be used separately or in another code without the consent of the
30 ! 3) This module may be used for research, educational, and non-profit purposes
31 ! only. Any other usage must be first approved by the PNNL contact.
32 ! 4) Publications resulting from the usage of this module must use one the
33 ! reference below for proper acknowledgment.
35 ! Note that the aerosol optical properites are currently tied to the use of Fast-J
36 ! and MOSAIC. Future modifications will make the calculations more generic so the
37 ! code is not tied to the photolysis scheme and the code can be used for both
38 ! modal and sectional treatments.
41 ! * Fast, J.D., W.I. Gustafson Jr., R.C. Easter, R.A. Zaveri, J.C. Barnard, E.G.
42 ! Chapman, G.A. Grell, and S.E. Peckham (2005), Evolution of ozone, particulates,
43 ! and aerosol direct radiative forcing in the vicinity of Houston using a fully-
44 ! coupled meteorology-chemistry-aerosol model, Submitted to J. Geophys. Res.
46 ! Contact Jerome Fast for updates on the status of manuscripts under review.
48 ! Additional information:
49 ! * www.pnl.gov/atmos_sciences/Jdf/wrfchem.html
52 ! Funding for adapting Fast-J was provided by the U.S. Department of Energy
53 ! under the auspices of Atmospheric Science Program of the Office of Biological
54 ! and Environmental Research the PNNL Laboratory Research and Directed Research
55 ! and Development program.
56 !**********************************************************************************
57 module module_fastj_mie
60 ! rce 2005-apr-22 - want lunerr = -1 for wrf-chem 3d;
61 ! also, define lunerr here, and it's available everywhere
62 integer, parameter :: lunerr = -1
67 !***********************************************************************
69 ! Purpose: calculate aerosol optical depth, single scattering albedo,
70 ! asymmetry factor, extinction, Legendre coefficients, and average aerosol
71 ! size. parameterizes aerosol coefficients using chebychev polynomials
72 ! requires double precision on 32-bit machines
73 ! uses Wiscombe's (1979) mie scattering code
75 ! id -- grid id number
76 ! iclm, jclm -- i,j of grid column being processed
77 ! nbin_a -- number of bins
78 ! number_bin(nbin_a,kmaxd) -- number density in layer, #/cm^3
79 ! radius_wet(nbin_a,kmaxd) -- wet radius, cm
80 ! refindx(nbin_a,kmaxd) --volume averaged complex index of refraction
81 ! dz -- depth of individual cells in column, m
82 ! isecfrm0 - time from start of run, sec
83 ! lpar -- number of grid cells in vertical (via module_fastj_cmnh)
84 ! kmaxd -- predefined maximum allowed levels from module_data_mosaic_other
85 ! passed here via module_fastj_cmnh
86 ! OUTPUT: saved in module_fastj_cmnmie
87 ! real tauaer ! aerosol optical depth
88 ! waer ! aerosol single scattering albedo
89 ! gaer ! aerosol asymmetery factor
90 ! extaer ! aerosol extinction
91 ! l2,l3,l4,l5,l6,l7 ! Legendre coefficients, numbered 0,1,2,......
92 ! sizeaer ! average wet radius
93 !----------------------------------------------------------------------
95 id, iclm, jclm, nbin_a, &
96 number_bin, radius_wet, refindx, &
98 sizeaer,extaer,waer,gaer,tauaer,l2,l3,l4,l5,l6,l7)
100 USE module_data_mosaic_other, only : kmaxd
101 USE module_data_mosaic_therm, ONLY: nbin_a_maxd
102 USE module_peg_util, only: peg_message
107 integer,parameter :: nspint = 4 ! Num of spectral intervals across
108 ! solar spectrum for FAST-J
109 integer, intent(in) :: lpar
110 real, dimension (nspint, kmaxd+1),intent(out) :: sizeaer,extaer,waer,gaer,tauaer
111 real, dimension (nspint, kmaxd+1),intent(out) :: l2,l3,l4,l5,l6,l7
112 real, dimension (nspint),save :: wavmid !cm
114 / 0.30e-4, 0.40e-4, 0.60e-4 ,0.999e-04 /
116 integer, intent(in) :: id, iclm, jclm, nbin_a, isecfrm0
117 real, intent(in), dimension(nbin_a_maxd, kmaxd) :: number_bin
118 real, intent(inout), dimension(nbin_a_maxd, kmaxd) :: radius_wet
119 complex, intent(in) :: refindx(nbin_a_maxd, kmaxd)
120 real, intent(in) :: dz(lpar)
123 real weighte, weights
124 ! various bookeeping variables
125 integer ltype ! total number of indicies of refraction
126 parameter (ltype = 1) ! bracket refractive indices based on information from Rahul, 2002/11/07
128 real thesum ! for normalizing things
129 real sizem ! size in microns
132 integer m, j, nc, klevel
133 real pext ! parameterized specific extinction (cm2/g)
134 real pasm ! parameterized asymmetry factor
135 real ppmom2 ! 2 Lengendre expansion coefficient (numbered 0,1,2,...)
142 integer ns ! Spectral loop index
143 integer i ! Longitude loop index
144 integer k ! Level loop index
145 real pscat !scattering cross section
147 integer prefr,prefi,nrefr,nrefi,nr,ni
149 parameter (prefr=7,prefi=7)
151 complex*16 sforw,sback,tforw(2),tback(2)
152 integer numang,nmom,ipolzn,momdim
154 logical perfct,anyang,prnt(2)
156 integer, parameter :: nsiz=200,nlog=30,ncoef=50
158 real p2(nsiz),p3(nsiz),p4(nsiz),p5(nsiz)
159 real p6(nsiz),p7(nsiz)
162 data xmu/1./,anyang/.false./
164 complex*16 s1(1),s2(1)
168 data perfct/.false./,mimcut/0.0/
169 data nmom/7/,ipolzn/0/,momdim/7/
170 data prnt/.false.,.false./
171 ! coefficients for parameterizing aerosol radiative properties
172 ! in terms of refractive index and wet radius
173 real extp(ncoef,prefr,prefi,nspint) ! specific extinction
174 real albp(ncoef,prefr,prefi,nspint) ! single scat alb
175 real asmp(ncoef,prefr,prefi,nspint) ! asymmetry factor
176 real ascat(ncoef,prefr,prefi,nspint) ! scattering efficiency, JCB 2004/02/09
177 real pmom2(ncoef,prefr,prefi,nspint) ! phase function expansion, #2
178 real pmom3(ncoef,prefr,prefi,nspint) ! phase function expansion, #3
179 real pmom4(ncoef,prefr,prefi,nspint) ! phase function expansion, #4
180 real pmom5(ncoef,prefr,prefi,nspint) ! phase function expansion, #5
181 real pmom6(ncoef,prefr,prefi,nspint) ! phase function expansion, #6
182 real pmom7(ncoef,prefr,prefi,nspint) ! phase function expansion, #7
184 save :: extp,albp,asmp,ascat,pmom2,pmom3,pmom4,pmom5,pmom6,pmom7
186 real cext(ncoef),casm(ncoef),cpmom2(ncoef)
187 real cscat(ncoef) ! JCB 2004/02/09
188 real cpmom3(ncoef),cpmom4(ncoef),cpmom5(ncoef)
189 real cpmom6(ncoef),cpmom7(ncoef)
193 ! nsiz = number of wet particle sizes
194 ! crefin = complex refractive index
196 real*8 thesize ! 2 pi radpart / waveleng = size parameter
197 real*8 qext(nsiz) ! array of extinction efficiencies
198 real*8 qsca(nsiz) ! array of scattering efficiencies
199 real*8 gqsc(nsiz) ! array of asymmetry factor * scattering efficiency
200 real asymm(nsiz) ! array of asymmetry factor
201 real scat(nsiz) ! JCB 2004/02/09
202 ! specabs = absorption coeff / unit dry mass
203 ! specscat = scattering coeff / unit dry mass
204 complex*16 crefin,crefd,crefw
206 real, save :: rmin,rmax ! min, max aerosol size bin
207 data rmin /0.005e-4/ ! rmin in cm. 5e-3 microns min allowable size
208 data rmax /50.e-4 / ! rmax in cm. 50 microns, big particle, max allowable size
212 real, save :: xrmin,xrmax,xr
213 real rs(nsiz) ! surface mode radius (cm)
214 real xrad ! normalized aerosol radius
215 real ch(ncoef) ! chebychev polynomial
217 real, save :: rhoh2o ! density of liquid water (g/cm3)
220 real refr ! real part of refractive index
221 real refi ! imaginary part of refractive index
222 real qextr4(nsiz) ! extinction, real*4
224 real refrmin ! minimum of real part of refractive index
225 real refrmax ! maximum of real part of refractive index
226 real refimin ! minimum of imag part of refractive index
227 real refimax ! maximum of imag part of refractive index
228 real drefr ! increment in real part of refractive index
229 real drefi ! increment in imag part of refractive index
230 real, save :: refrtab(prefr) ! table of real refractive indices for aerosols
231 real, save :: refitab(prefi) ! table of imag refractive indices for aerosols
232 complex specrefndx(ltype) ! refractivr indices
236 ! diagnostic declarations
241 #if (defined(CHEM_DBG_I) && defined(CHEM_DBG_J) && defined(CHEM_DBG_K))
242 !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
244 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
245 !ec run_out.25 has aerosol physical parameter info for bins 1-8
246 !ec and vertical cells 1 to kmaxd.
249 if (iclm .eq. CHEM_DBG_I) then
250 if (jclm .eq. CHEM_DBG_J) then
252 if (kcallmieaer2 .eq. 0) then
253 write(*,9099)iclm, jclm
254 9099 format('for cell i = ', i3, 2x, 'j = ', i3)
257 'isecfrm0', 3x, 'i', 3x, 'j', 3x,'k', 3x, &
259 'refindx(ibin,k)', 3x, &
260 'radius_wet(ibin,k)', 3x, &
261 'number_bin(ibin,k)' &
264 !ec output for run_out.25
268 isecfrm0,iclm, jclm, k, ibin, &
270 radius_wet(ibin,k), &
272 9120 format( i7,3(2x,i4),2x,i4, 4x, 4(e14.6,2x))
275 kcallmieaer2 = kcallmieaer2 + 1
278 !ec end print of aerosol physical parameter diagnostics
279 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
282 ! assign fast-J wavelength, these values are in cm
286 ! wavmid(4)=0.999e-04
293 ! parameterize aerosol radiative properties in terms of
294 ! relative humidity, surface mode wet radius, aerosol species,
297 ! first find min,max of real and imaginary parts of refractive index
299 ! real and imaginary parts of water refractive index
301 crefw=cmplx(1.33,0.0)
304 ! change Rahul's imaginary part of the refractive index from positive to negative
309 specrefndx(1)=cmplx(1.82,-0.74) ! max values from Rahul, 7 Nov 2002
312 do i=1,ltype ! loop over all possible refractive indices
314 ! real and imaginary parts of aerosol refractive index
316 refrmin=amin1(refrmin,real(specrefndx(ltype)))
317 refrmax=amax1(refrmax,real(specrefndx(ltype)))
318 refimin=amin1(refimin,aimag(specrefndx(ltype)))
319 refimax=amax1(refimax,aimag(specrefndx(ltype)))
323 drefr=(refrmax-refrmin)
324 if(drefr.gt.1.e-4)then
326 drefr=drefr/(nrefr-1)
331 drefi=(refimax-refimin)
332 if(drefi.gt.1.e-4)then
334 drefi=drefi/(nrefi-1)
341 bma=0.5*alog(rmax/rmin) ! JCB
342 bpa=0.5*alog(rmax*rmin) ! JCB
350 ! calibrate parameterization with range of refractive indices
355 refrtab(nr)=refrmin+(nr-1)*drefr
356 refitab(ni)=refimin+(ni-1)*drefi
357 crefd=cmplx(refrtab(nr),refitab(ni))
359 ! mie calculations of optical efficiencies
362 xr=cos(pie*(float(n)-0.5)/float(nsiz))
363 rs(n)=exp(xr*bma+bpa)
366 ! size parameter and weighted refractive index
368 thesize=2.*pie*rs(n)/wavmid(ns)
369 thesize=min(thesize,10000.d0)
371 call miev0(thesize,crefd,perfct,mimcut,anyang, &
372 numang,xmu,nmom,ipolzn,momdim,prnt, &
373 qext(n),qsca(n),gqsc(n),pmom,sforw,sback,s1, &
376 ! qabs(n)=qext(n)-qsca(n) ! not necessary anymore JCB 2004/02/09
377 scat(n)=qsca(n) ! JCB 2004/02/09
378 asymm(n)=gqsc(n)/qsca(n) ! assume always greater than zero
379 ! coefficients of phase function expansion; note modification by JCB of miev0 coefficients
380 p2(n)=pmom(2,1)/pmom(0,1)*5.0
381 p3(n)=pmom(3,1)/pmom(0,1)*7.0
382 p4(n)=pmom(4,1)/pmom(0,1)*9.0
383 p5(n)=pmom(5,1)/pmom(0,1)*11.0
384 p6(n)=pmom(6,1)/pmom(0,1)*13.0
385 p7(n)=pmom(7,1)/pmom(0,1)*15.0
389 call fitcurv(rs,qextr4,extp(1,nr,ni,ns),ncoef,nsiz)
390 call fitcurv(rs,scat,ascat(1,nr,ni,ns),ncoef,nsiz) ! JCB 2004/02/07 - scattering efficiency
391 call fitcurv(rs,asymm,asmp(1,nr,ni,ns),ncoef,nsiz)
392 call fitcurv_nolog(rs,p2,pmom2(1,nr,ni,ns),ncoef,nsiz)
393 call fitcurv_nolog(rs,p3,pmom3(1,nr,ni,ns),ncoef,nsiz)
394 call fitcurv_nolog(rs,p4,pmom4(1,nr,ni,ns),ncoef,nsiz)
395 call fitcurv_nolog(rs,p5,pmom5(1,nr,ni,ns),ncoef,nsiz)
396 call fitcurv_nolog(rs,p6,pmom6(1,nr,ni,ns),ncoef,nsiz)
397 call fitcurv_nolog(rs,p7,pmom7(1,nr,ni,ns),ncoef,nsiz)
405 do 2000 klevel=1,lpar
406 ! sum densities for normalization
409 thesum=thesum+number_bin(m,klevel)
411 ! Begin spectral loop
414 ! aerosol optical properties
419 sizeaer(ns,klevel)=0.0
420 extaer(ns,klevel)=0.0
427 if(thesum.le.1e-21)goto 1000 ! set everything = 0 if no aerosol !wig changed 0.0 to 1e-21, 31-Oct-2005
430 do m=1,nbin_a ! nbin_a is number of bins
431 ! check to see if there's any aerosol
432 if(number_bin(m,klevel).le.1e-21)goto 70 ! no aerosol !wig changed 0.0 to 1e-21, 31-Oct-2005
434 sizem=radius_wet(m,klevel) ! radius in cm
435 ! check limits of particle size
436 ! rce 2004-dec-07 - use klevel in write statements
437 if(radius_wet(m,klevel).le.rmin)then
438 radius_wet(m,klevel)=rmin
439 write( msg, '(a, 5i4,1x, e11.4)' ) &
440 'FASTJ mie: radius_wet set to rmin,' // &
441 'id,i,j,k,m,rm(m,k)', id, iclm, jclm, klevel, m, radius_wet(m,klevel)
442 call peg_message( lunerr, msg )
443 ! write(6,'('' particle size too small '')')
446 if(radius_wet(m,klevel).gt.rmax)then
447 write( msg, '(a, 5i4,1x, e11.4)' ) &
448 'FASTJ mie: radius_wet set to rmax,' // &
449 'id,i,j,k,m,rm(m,k)', &
450 id, iclm, jclm, klevel, m, radius_wet(m,klevel)
451 call peg_message( lunerr, msg )
452 radius_wet(m,klevel)=rmax
453 ! write(6,'('' particle size too large '')')
456 x=alog(radius_wet(m,klevel)) ! radius in cm
458 crefin=refindx(m,klevel)
460 ! change Rahul's imaginary part of the index of refraction from positive to negative
465 thesize=2.0*pie*exp(x)/wavmid(ns)
466 ! normalize size parameter
467 xrad=(2*xrad-xrmax-xrmin)/(xrmax-xrmin)
468 ! retain this diagnostic code
469 if(abs(refr).gt.10.0.or.abs(refr).le.0.001)then
470 write ( msg, '(a,1x, e14.5)' ) &
471 'FASTJ mie /refr/ outside range 1e-3 - 10 ' // &
473 call peg_message( lunerr, msg )
474 ! print *,'refr=',refr
477 if(abs(refi).gt.10.)then
478 write ( msg, '(a,1x, e14.5)' ) &
479 'FASTJ mie /refi/ >10 ' // &
481 call peg_message( lunerr, msg )
482 ! print *,'refi=',refi
486 ! interpolate coefficients linear in refractive index
487 ! first call calcs itab,jtab,ttab,utab
489 call binterp(extp(1,1,1,ns),ncoef,nrefr,nrefi, &
490 refr,refi,refrtab,refitab,itab,jtab, &
493 ! JCB 2004/02/09 -- new code for scattering cross section
494 call binterp(ascat(1,1,1,ns),ncoef,nrefr,nrefi, &
495 refr,refi,refrtab,refitab,itab,jtab, &
497 call binterp(asmp(1,1,1,ns),ncoef,nrefr,nrefi, &
498 refr,refi,refrtab,refitab,itab,jtab, &
500 call binterp(pmom2(1,1,1,ns),ncoef,nrefr,nrefi, &
501 refr,refi,refrtab,refitab,itab,jtab, &
503 call binterp(pmom3(1,1,1,ns),ncoef,nrefr,nrefi, &
504 refr,refi,refrtab,refitab,itab,jtab, &
506 call binterp(pmom4(1,1,1,ns),ncoef,nrefr,nrefi, &
507 refr,refi,refrtab,refitab,itab,jtab, &
509 call binterp(pmom5(1,1,1,ns),ncoef,nrefr,nrefi, &
510 refr,refi,refrtab,refitab,itab,jtab, &
512 call binterp(pmom6(1,1,1,ns),ncoef,nrefr,nrefi, &
513 refr,refi,refrtab,refitab,itab,jtab, &
515 call binterp(pmom7(1,1,1,ns),ncoef,nrefr,nrefi, &
516 refr,refi,refrtab,refitab,itab,jtab, &
519 ! chebyshev polynomials
524 ch(nc)=2.*xrad*ch(nc-1)-ch(nc-2)
526 ! parameterized optical properties
530 pext=pext+ch(nc)*cext(nc)
534 ! JCB 2004/02/09 -- for scattering efficiency
537 pscat=pscat+ch(nc)*cscat(nc)
543 pasm=pasm+ch(nc)*casm(nc)
549 ppmom2=ppmom2+ch(nc)*cpmom2(nc)
551 if(ppmom2.le.0.0)ppmom2=0.0
555 ppmom3=ppmom3+ch(nc)*cpmom3(nc)
557 ! ppmom3=exp(ppmom3) ! no exponentiation required
558 if(ppmom3.le.0.0)ppmom3=0.0
562 ppmom4=ppmom4+ch(nc)*cpmom4(nc)
564 if(ppmom4.le.0.0.or.sizem.le.0.03e-04)ppmom4=0.0
568 ppmom5=ppmom5+ch(nc)*cpmom5(nc)
570 if(ppmom5.le.0.0.or.sizem.le.0.03e-04)ppmom5=0.0
574 ppmom6=ppmom6+ch(nc)*cpmom6(nc)
576 if(ppmom6.le.0.0.or.sizem.le.0.03e-04)ppmom6=0.0
580 ppmom7=ppmom7+ch(nc)*cpmom7(nc)
582 if(ppmom7.le.0.0.or.sizem.le.0.03e-04)ppmom7=0.0
585 weighte=pext*pie*exp(x)**2 ! JCB, extinction cross section
586 weights=pscat*pie*exp(x)**2 ! JCB, scattering cross section
587 tauaer(ns,klevel)=tauaer(ns,klevel)+weighte*number_bin(m,klevel) ! must be multiplied by deltaZ
588 extaer(ns,klevel)=extaer(ns,klevel)+pext*number_bin(m,klevel)
589 sizeaer(ns,klevel)=sizeaer(ns,klevel)+exp(x)*10000.0* &
591 waer(ns,klevel)=waer(ns,klevel)+weights*number_bin(m,klevel) !JCB
592 gaer(ns,klevel)=gaer(ns,klevel)+pasm*weights* &
593 number_bin(m,klevel) !JCB
594 ! need weighting by scattering cross section ? JCB 2004/02/09
595 l2(ns,klevel)=l2(ns,klevel)+weights*ppmom2*number_bin(m,klevel)
596 l3(ns,klevel)=l3(ns,klevel)+weights*ppmom3*number_bin(m,klevel)
597 l4(ns,klevel)=l4(ns,klevel)+weights*ppmom4*number_bin(m,klevel)
598 l5(ns,klevel)=l5(ns,klevel)+weights*ppmom5*number_bin(m,klevel)
599 l6(ns,klevel)=l6(ns,klevel)+weights*ppmom6*number_bin(m,klevel)
600 l7(ns,klevel)=l7(ns,klevel)+weights*ppmom7*number_bin(m,klevel)
602 end do ! end of nbin_a loop
603 ! take averages - weighted by cross section - new code JCB 2004/02/09
604 extaer(ns,klevel)=extaer(ns,klevel)/thesum
605 sizeaer(ns,klevel)=sizeaer(ns,klevel)/thesum
606 gaer(ns,klevel)=gaer(ns,klevel)/waer(ns,klevel) ! JCB removed *3 factor 2/9/2004
607 ! because factor is applied in subroutine opmie, file zz01fastj_mod.f
608 l2(ns,klevel)=l2(ns,klevel)/waer(ns,klevel)
609 l3(ns,klevel)=l3(ns,klevel)/waer(ns,klevel)
610 l4(ns,klevel)=l4(ns,klevel)/waer(ns,klevel)
611 l5(ns,klevel)=l5(ns,klevel)/waer(ns,klevel)
612 l6(ns,klevel)=l6(ns,klevel)/waer(ns,klevel)
613 l7(ns,klevel)=l7(ns,klevel)/waer(ns,klevel)
614 ! this must be last!! JCB 2007/02/09
615 waer(ns,klevel)=waer(ns,klevel)/tauaer(ns,klevel) ! JCB
617 70 continue ! bail out if no aerosol;go on to next wavelength bin
619 1000 continue ! end of wavelength loop
622 2000 continue ! end of klevel loop
624 ! before returning, multiply tauaer by depth of individual cells.
625 ! tauaer is in cm, dz in m; multiply dz by 100 to convert from m to cm.
628 tauaer(ns,klevel) = tauaer(ns,klevel) * dz(klevel)* 100.
632 #if (defined(CHEM_DBG_I) && defined(CHEM_DBG_J) && defined(CHEM_DBG_K))
633 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
634 !ec fastj diagnostics
635 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
636 !ec run_out.30 has aerosol optical info for cells 1 to kmaxd.
639 if (iclm .eq. CHEM_DBG_I) then
640 if (jclm .eq. CHEM_DBG_J) then
642 if (kcallmieaer .eq. 0) then
643 write(*,909) CHEM_DBG_I, CHEM_DBG_J
644 909 format( ' for cell i = ', i3, ' j = ', i3)
647 'isecfrm0', 3x, 'i', 3x, 'j', 3x,'k', 3x, &
649 'tauaer(1,k)',1x, 'tauaer(2,k)',1x,'tauaer(3,k)',3x, &
651 'waer(1,k)', 7x, 'waer(2,k)', 7x,'waer(3,k)', 7x, &
653 'gaer(1,k)', 7x, 'gaer(2,k)', 7x,'gaer(3,k)', 7x, &
655 'extaer(1,k)',5x, 'extaer(2,k)',5x,'extaer(3,k)',5x, &
657 'sizeaer(1,k)',4x, 'sizeaer(2,k)',4x,'sizeaer(3,k)',4x, &
660 !ec output for run_out.30
663 isecfrm0,iclm, jclm, k, &
665 (tauaer(n,k), n=1,4), &
666 (waer(n,k), n=1,4), &
667 (gaer(n,k), n=1,4), &
668 (extaer(n,k), n=1,4), &
669 (sizeaer(n,k), n=1,4)
670 912 format( i7,3(2x,i4),2x,21(e14.6,2x))
672 kcallmieaer = kcallmieaer + 1
675 !ec end print of fastj diagnostics
676 !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
680 end subroutine mieaer
681 !****************************************************************
682 subroutine fitcurv(rs,yin,coef,ncoef,maxm)
684 ! fit y(x) using Chebychev polynomials
685 ! wig 7-Sep-2004: Removed dependency on pre-determined maximum
686 ! array size and replaced with f90 array info.
688 USE module_peg_util, only: peg_message
691 ! integer nmodes, nrows, maxm, ncoef
692 ! parameter (nmodes=500,nrows=8)
693 integer, intent(in) :: maxm, ncoef
695 ! real rs(nmodes),yin(nmodes),coef(ncoef)
696 ! real x(nmodes),y(nmodes)
697 real, dimension(ncoef) :: coef
698 real, dimension(:) :: rs, yin
699 real x(size(rs)),y(size(yin))
705 !!$ if(maxm.gt.nmodes)then
706 !!$ write ( msg, '(a, 1x,i6)' ) &
707 !!$ 'FASTJ mie nmodes too small in fitcurv, ' // &
709 !!$ call peg_message( lunerr, msg )
710 !!$! write(*,*)'nmodes too small in fitcurv',maxm
722 x(m)=(2*x(m)-xmax-xmin)/(xmax-xmin)
725 call chebft(coef,ncoef,maxm,y)
728 end subroutine fitcurv
729 !**************************************************************
730 subroutine fitcurv_nolog(rs,yin,coef,ncoef,maxm)
732 ! fit y(x) using Chebychev polynomials
733 ! wig 7-Sep-2004: Removed dependency on pre-determined maximum
734 ! array size and replaced with f90 array info.
736 USE module_peg_util, only: peg_message
739 ! integer nmodes, nrows, maxm, ncoef
740 ! parameter (nmodes=500,nrows=8)
741 integer, intent(in) :: maxm, ncoef
743 ! real rs(nmodes),yin(nmodes),coef(ncoef)
744 real, dimension(:) :: rs, yin
745 real, dimension(ncoef) :: coef(ncoef)
746 real x(size(rs)),y(size(yin))
752 !!$ if(maxm.gt.nmodes)then
753 !!$ write ( msg, '(a,1x, i6)' ) &
754 !!$ 'FASTJ mie nmodes too small in fitcurv ' // &
756 !!$ call peg_message( lunerr, msg )
757 !!$! write(*,*)'nmodes too small in fitcurv',maxm
763 y(m)=yin(m) ! note, no "alog" here
769 x(m)=(2*x(m)-xmax-xmin)/(xmax-xmin)
772 call chebft(coef,ncoef,maxm,y)
775 end subroutine fitcurv_nolog
776 !************************************************************************
777 subroutine chebft(c,ncoef,n,f)
778 ! given a function f with values at zeroes x_k of Chebychef polynomial
779 ! T_n(x), calculate coefficients c_j such that
780 ! f(x)=sum(k=1,n) c_k t_(k-1)(y) - 0.5*c_1
781 ! where y=(x-0.5*(xmax+xmin))/(0.5*(xmax-xmin))
782 ! See Numerical Recipes, pp. 148-150.
787 parameter (pi=3.14159265)
798 thesum=thesum+f(k)*cos((pi*(j-1))*((k-0.5)/n))
803 end subroutine chebft
804 !*************************************************************************
805 subroutine binterp(table,km,im,jm,x,y,xtab,ytab,ix,jy,t,u,out)
807 ! bilinear interpolation of table
811 real table(km,im,jm),xtab(im),ytab(jm),out(km)
812 integer i,ix,ip1,j,jy,jp1,k
813 real x,dx,t,y,dy,u,tu, tuc,tcu,tcuc
818 if(x.lt.xtab(i))go to 10
822 dx=(xtab(ip1)-xtab(ix))
823 if(abs(dx).gt.1.e-20)then
824 t=(x-xtab(ix))/(xtab(ix+1)-xtab(ix))
835 if(y.lt.ytab(j))go to 20
839 dy=(ytab(jp1)-ytab(jy))
840 if(abs(dy).gt.1.e-20)then
858 out(k)=tcuc*table(k,ix,jy)+tuc*table(k,ip1,jy) &
859 +tu*table(k,ip1,jp1)+tcu*table(k,ix,jp1)
862 end subroutine binterp
863 !***************************************************************
864 subroutine miev0 ( xx, crefin, perfct, mimcut, anyang, &
865 numang, xmu, nmom, ipolzn, momdim, prnt, &
866 qext, qsca, gqsc, pmom, sforw, sback, s1, &
869 ! computes mie scattering and extinction efficiencies; asymmetry
870 ! factor; forward- and backscatter amplitude; scattering
871 ! amplitudes for incident polarization parallel and perpendicular
872 ! to the plane of scattering, as functions of scattering angle;
873 ! coefficients in the legendre polynomial expansions of either the
874 ! unpolarized phase function or the polarized phase matrix;
875 ! and some quantities needed in polarized radiative transfer.
877 ! calls : biga, ckinmi, small1, small2, testmi, miprnt,
880 ! i n t e r n a l v a r i a b l e s
881 ! -----------------------------------
883 ! an,bn mie coefficients little-a-sub-n, little-b-sub-n
885 ! anm1,bnm1 mie coefficients little-a-sub-(n-1),
886 ! little-b-sub-(n-1); used in -gqsc- sum
887 ! anp coeffs. in s+ expansion ( ref. 2, p. 1507 )
888 ! bnp coeffs. in s- expansion ( ref. 2, p. 1507 )
889 ! anpm coeffs. in s+ expansion ( ref. 2, p. 1507 )
890 ! when mu is replaced by - mu
891 ! bnpm coeffs. in s- expansion ( ref. 2, p. 1507 )
892 ! when mu is replaced by - mu
893 ! calcmo(k) true, calculate moments for k-th phase quantity
894 ! (derived from -ipolzn-; used only in 'lpcoef')
895 ! cbiga(n) bessel function ratio capital-a-sub-n (ref. 2, eq. 2)
896 ! ( complex version )
897 ! cior complex index of refraction with negative
898 ! imaginary part (van de hulst convention)
900 ! coeff ( 2n + 1 ) / ( n ( n + 1 ) )
901 ! fn floating point version of index in loop performing
902 ! mie series summation
903 ! lita,litb(n) mie coefficients -an-, -bn-, saved in arrays for
904 ! use in calculating legendre moments *pmom*
905 ! maxtrm max. possible no. of terms in mie series
906 ! mm + 1 and - 1, alternately.
907 ! mim magnitude of imaginary refractive index
908 ! mre real part of refractive index
909 ! maxang max. possible value of input variable -numang-
910 ! nangd2 (numang+1)/2 ( no. of angles in 0-90 deg; anyang=f )
911 ! noabs true, sphere non-absorbing (determined by -mimcut-)
912 ! np1dn ( n + 1 ) / n
913 ! npquan highest-numbered phase quantity for which moments are
914 ! to be calculated (the largest digit in -ipolzn-
916 ! ntrm no. of terms in mie series
917 ! pass1 true on first entry, false thereafter; for self-test
918 ! pin(j) angular function little-pi-sub-n ( ref. 2, eq. 3 )
920 ! pinm1(j) little-pi-sub-(n-1) ( see -pin- ) at j-th angle
921 ! psinm1 ricatti-bessel function psi-sub-(n-1), argument -xx-
922 ! psin ricatti-bessel function psi-sub-n of argument -xx-
923 ! ( ref. 1, p. 11 ff. )
924 ! rbiga(n) bessel function ratio capital-a-sub-n (ref. 2, eq. 2)
925 ! ( real version, for when imag refrac index = 0 )
928 ! rtmp (real) temporary variable
929 ! sp(j) s+ for j-th angle ( ref. 2, p. 1507 )
930 ! sm(j) s- for j-th angle ( ref. 2, p. 1507 )
931 ! sps(j) s+ for (numang+1-j)-th angle ( anyang=false )
932 ! sms(j) s- for (numang+1-j)-th angle ( anyang=false )
933 ! taun angular function little-tau-sub-n ( ref. 2, eq. 4 )
935 ! tcoef n ( n+1 ) ( 2n+1 ) (for summing tforw,tback series)
937 ! yesang true if scattering amplitudes are to be calculated
938 ! zetnm1 ricatti-bessel function zeta-sub-(n-1) of argument
939 ! -xx- ( ref. 2, eq. 17 )
940 ! zetn ricatti-bessel function zeta-sub-n of argument -xx-
942 ! ----------------------------------------------------------------------
943 ! -------- i / o specifications for subroutine miev0 -----------------
944 ! ----------------------------------------------------------------------
946 logical anyang, perfct, prnt(*)
947 integer ipolzn, momdim, numang, nmom
948 real*8 gqsc, mimcut, pmom( 0:momdim, * ), qext, qsca, &
950 complex*16 crefin, sforw, sback, s1(*), s2(*), tforw(*), &
952 integer maxang,mxang2,maxtrm
954 ! ----------------------------------------------------------------------
956 parameter ( maxang = 501, mxang2 = maxang/2 + 1 )
958 ! ** note -- maxtrm = 10100 is neces-
959 ! ** sary to do some of the test probs,
960 ! ** but 1100 is sufficient for most
961 ! ** conceivable applications
962 parameter ( maxtrm = 1100 )
963 parameter ( onethr = 1./3. )
965 logical anysav, calcmo(4), noabs, ok, pass1, persav, yesang
967 integer i,j,n,nmosav,iposav,numsav,ntrm,nangd2
968 real*8 mim, mimsav, mre, mm, np1dn
969 real*8 rioriv,xmusav,xxsav,sq,fn,rn,twonp1,tcoef, coeff
970 real*8 xinv,psinm1,chinm1,psin,chin,rtmp,taun
971 real*8 rbiga( maxtrm ), pin( maxang ), pinm1( maxang )
972 complex*16 an, bn, anm1, bnm1, anp, bnp, anpm, bnpm, cresav, &
973 cior, cioriv, ctmp, zet, zetnm1, zetn
974 complex*16 cbiga( maxtrm ), lita( maxtrm ), litb( maxtrm ), &
975 sp( maxang ), sm( maxang ), sps( mxang2 ), sms( mxang2 )
976 equivalence ( cbiga, rbiga )
978 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
979 data pass1 / .true. /
983 ! ** save certain user input values
993 ! ** reset input values for test case
995 crefin = ( 1.5, - 0.1 )
1000 xmu( 1 )= - 0.7660444
1005 ! ** check input and calculate
1006 ! ** certain variables from input
1008 10 call ckinmi( numang, maxang, xx, perfct, crefin, momdim, &
1009 nmom, ipolzn, anyang, xmu, calcmo, npquan )
1011 if ( perfct .and. xx .le. 0.1 ) then
1012 ! ** use totally-reflecting
1013 ! ** small-particle limit
1015 call small1 ( xx, numang, xmu, qext, qsca, gqsc, sforw, &
1016 sback, s1, s2, tforw, tback, lita, litb )
1021 if ( .not.perfct ) then
1024 if ( dimag( cior ) .gt. 0.0 ) cior = dconjg( cior )
1026 mim = - dimag( cior )
1027 noabs = mim .le. mimcut
1031 if ( xx * dmax1( 1.d0, cdabs(cior) ) .le. 0.d1 ) then
1033 ! ** use general-refractive-index
1034 ! ** small-particle limit
1035 ! ** ( ref. 2, p. 1508 )
1037 call small2 ( xx, cior, .not.noabs, numang, xmu, qext, &
1038 qsca, gqsc, sforw, sback, s1, s2, tforw, &
1046 nangd2 = ( numang + 1 ) / 2
1047 yesang = numang .gt. 0
1048 ! ** estimate number of terms in mie series
1049 ! ** ( ref. 2, p. 1508 )
1050 if ( xx.le.8.0 ) then
1051 ntrm = xx + 4. * xx**onethr + 1.
1052 else if ( xx.lt.4200. ) then
1053 ntrm = xx + 4.05 * xx**onethr + 2.
1055 ntrm = xx + 4. * xx**onethr + 2.
1057 if ( ntrm+1 .gt. maxtrm ) &
1058 call errmsg( 'miev0--parameter maxtrm too small', .true. )
1060 ! ** calculate logarithmic derivatives of
1061 ! ** j-bessel-fcn., big-a-sub-(1 to ntrm)
1062 if ( .not.perfct ) &
1063 call biga( cior, xx, ntrm, noabs, yesang, rbiga, cbiga )
1065 ! ** initialize ricatti-bessel functions
1066 ! ** (psi,chi,zeta)-sub-(0,1) for upward
1067 ! ** recurrence ( ref. 1, eq. 19 )
1071 psin = psinm1 * xinv - chinm1
1072 chin = chinm1 * xinv + psinm1
1073 zetnm1 = dcmplx( psinm1, chinm1 )
1074 zetn = dcmplx( psin, chin )
1075 ! ** initialize previous coeffi-
1076 ! ** cients for -gqsc- series
1079 ! ** initialize angular function little-pi
1080 ! ** and sums for s+, s- ( ref. 2, p. 1507 )
1085 sp ( j ) = ( 0.0, 0.0 )
1086 sm ( j ) = ( 0.0, 0.0 )
1092 sp ( j ) = ( 0.0, 0.0 )
1093 sm ( j ) = ( 0.0, 0.0 )
1094 sps( j ) = ( 0.0, 0.0 )
1095 sms( j ) = ( 0.0, 0.0 )
1098 ! ** initialize mie sums for efficiencies, etc.
1103 tforw( 1 ) = ( 0., 0. )
1104 tback( 1 ) = ( 0., 0. )
1107 ! --------- loop to sum mie series -----------------------------------
1111 ! ** compute various numerical coefficients
1116 coeff = twonp1 / ( fn * ( n + 1 ) )
1117 tcoef = twonp1 * ( fn * ( n + 1 ) )
1119 ! ** calculate mie series coefficients
1121 ! ** totally-reflecting case
1123 an = ( ( fn*xinv ) * psin - psinm1 ) / &
1124 ( ( fn*xinv ) * zetn - zetnm1 )
1127 else if ( noabs ) then
1128 ! ** no-absorption case
1130 an = ( ( rioriv*rbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1131 / ( ( rioriv*rbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1132 bn = ( ( mre * rbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1133 / ( ( mre * rbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1135 ! ** absorptive case
1137 an = ( ( cioriv * cbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1138 /( ( cioriv * cbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1139 bn = ( ( cior * cbiga(n) + ( fn*xinv ) ) * psin - psinm1 ) &
1140 /( ( cior * cbiga(n) + ( fn*xinv ) ) * zetn - zetnm1 )
1141 qsca = qsca + twonp1 * ( sq( an ) + sq( bn ) )
1144 ! ** save mie coefficients for *pmom* calculation
1147 ! ** increment mie sums for non-angle-
1148 ! ** dependent quantities
1150 sforw = sforw + twonp1 * ( an + bn )
1151 tforw( 1 ) = tforw( 1 ) + tcoef * ( an - bn )
1152 sback = sback + ( mm * twonp1 ) * ( an - bn )
1153 tback( 1 ) = tback( 1 ) + ( mm * tcoef ) * ( an + bn )
1154 gqsc = gqsc + ( fn - rn ) * dble( anm1 * dconjg( an ) &
1155 + bnm1 * dconjg( bn ) ) &
1156 + coeff * dble( an * dconjg( bn ) )
1159 ! ** put mie coefficients in form
1160 ! ** needed for computing s+, s-
1161 ! ** ( ref. 2, p. 1507 )
1162 anp = coeff * ( an + bn )
1163 bnp = coeff * ( an - bn )
1164 ! ** increment mie sums for s+, s-
1165 ! ** while upward recursing
1166 ! ** angular functions little pi
1169 ! ** arbitrary angles
1171 ! ** vectorizable loop
1173 rtmp = ( xmu( j ) * pin( j ) ) - pinm1( j )
1174 taun = fn * rtmp - pinm1( j )
1175 sp( j ) = sp( j ) + anp * ( pin( j ) + taun )
1176 sm( j ) = sm( j ) + bnp * ( pin( j ) - taun )
1177 pinm1( j ) = pin( j )
1178 pin( j ) = ( xmu( j ) * pin( j ) ) + np1dn * rtmp
1182 ! ** angles symmetric about 90 degrees
1185 ! ** vectorizable loop
1187 rtmp = ( xmu( j ) * pin( j ) ) - pinm1( j )
1188 taun = fn * rtmp - pinm1( j )
1189 sp ( j ) = sp ( j ) + anp * ( pin( j ) + taun )
1190 sms( j ) = sms( j ) + bnpm * ( pin( j ) + taun )
1191 sm ( j ) = sm ( j ) + bnp * ( pin( j ) - taun )
1192 sps( j ) = sps( j ) + anpm * ( pin( j ) - taun )
1193 pinm1( j ) = pin( j )
1194 pin( j ) = ( xmu( j ) * pin( j ) ) + np1dn * rtmp
1199 ! ** update relevant quantities for next
1200 ! ** pass through loop
1204 ! ** upward recurrence for ricatti-bessel
1205 ! ** functions ( ref. 1, eq. 17 )
1207 zet = ( twonp1 * xinv ) * zetn - zetnm1
1214 ! ---------- end loop to sum mie series --------------------------------
1217 qext = 2. / xx**2 * dble( sforw )
1218 if ( perfct .or. noabs ) then
1221 qsca = 2. / xx**2 * qsca
1224 gqsc = 4. / xx**2 * gqsc
1227 tforw( 2 ) = 0.5 * ( sforw + 0.25 * tforw( 1 ) )
1228 tforw( 1 ) = 0.5 * ( sforw - 0.25 * tforw( 1 ) )
1229 tback( 2 ) = 0.5 * ( sback + 0.25 * tback( 1 ) )
1230 tback( 1 ) = 0.5 * ( - sback + 0.25 * tback( 1 ) )
1233 ! ** recover scattering amplitudes
1234 ! ** from s+, s- ( ref. 1, eq. 11 )
1236 ! ** vectorizable loop
1237 do 110 j = 1, numang
1238 s1( j ) = 0.5 * ( sp( j ) + sm( j ) )
1239 s2( j ) = 0.5 * ( sp( j ) - sm( j ) )
1243 ! ** vectorizable loop
1244 do 120 j = 1, nangd2
1245 s1( j ) = 0.5 * ( sp( j ) + sm( j ) )
1246 s2( j ) = 0.5 * ( sp( j ) - sm( j ) )
1248 ! ** vectorizable loop
1249 do 130 j = 1, nangd2
1250 s1( numang+1 - j ) = 0.5 * ( sps( j ) + sms( j ) )
1251 s2( numang+1 - j ) = 0.5 * ( sps( j ) - sms( j ) )
1256 ! ** calculate legendre moments
1257 200 if ( nmom.gt.0 ) &
1258 call lpcoef ( ntrm, nmom, ipolzn, momdim, calcmo, npquan, &
1261 if ( dimag(crefin) .gt. 0.0 ) then
1262 ! ** take complex conjugates
1263 ! ** of scattering amplitudes
1264 sforw = dconjg( sforw )
1265 sback = dconjg( sback )
1267 tforw( i ) = dconjg( tforw(i) )
1268 tback( i ) = dconjg( tback(i) )
1271 do 220 j = 1, numang
1272 s1( j ) = dconjg( s1(j) )
1273 s2( j ) = dconjg( s2(j) )
1279 ! ** compare test case results with
1280 ! ** correct answers and abort if bad
1282 call testmi ( qext, qsca, gqsc, sforw, sback, s1, s2, &
1283 tforw, tback, pmom, momdim, ok )
1284 if ( .not. ok ) then
1287 call miprnt( prnt, xx, perfct, crefin, numang, xmu, qext, &
1288 qsca, gqsc, nmom, ipolzn, momdim, calcmo, &
1289 pmom, sforw, sback, tforw, tback, s1, s2 )
1290 call errmsg( 'miev0 -- self-test failed', .true. )
1292 ! ** restore user input values
1307 if ( prnt(1) .or. prnt(2) ) &
1308 call miprnt( prnt, xx, perfct, crefin, numang, xmu, qext, &
1309 qsca, gqsc, nmom, ipolzn, momdim, calcmo, &
1310 pmom, sforw, sback, tforw, tback, s1, s2 )
1314 end subroutine miev0
1315 !****************************************************************************
1316 subroutine ckinmi( numang, maxang, xx, perfct, crefin, momdim, &
1317 nmom, ipolzn, anyang, xmu, calcmo, npquan )
1319 ! check for bad input to 'miev0' and calculate -calcmo,npquan-
1322 logical perfct, anyang, calcmo(*)
1323 integer numang, maxang, momdim, nmom, ipolzn, npquan
1333 if ( numang.gt.maxang ) then
1334 call errmsg( 'miev0--parameter maxang too small', .true. )
1337 if ( numang.lt.0 ) call wrtbad( 'numang', inperr )
1338 if ( xx.lt.0. ) call wrtbad( 'xx', inperr )
1339 if ( .not.perfct .and. dble(crefin).le.0. ) &
1340 call wrtbad( 'crefin', inperr )
1341 if ( momdim.lt.1 ) call wrtbad( 'momdim', inperr )
1343 if ( nmom.ne.0 ) then
1344 if ( nmom.lt.0 .or. nmom.gt.momdim ) call wrtbad('nmom',inperr)
1345 if ( iabs(ipolzn).gt.4444 ) call wrtbad( 'ipolzn', inperr )
1348 calcmo( l ) = .false.
1350 if ( ipolzn.ne.0 ) then
1351 ! ** parse out -ipolzn- into its digits
1352 ! ** to find which phase quantities are
1353 ! ** to have their moments calculated
1355 write( string, '(i4)' ) iabs(ipolzn)
1357 ip = ichar( string(j:j) ) - ichar( '0' )
1358 if ( ip.ge.1 .and. ip.le.4 ) calcmo( ip ) = .true.
1359 if ( ip.eq.0 .or. (ip.ge.5 .and. ip.le.9) ) &
1360 call wrtbad( 'ipolzn', inperr )
1361 npquan = max0( npquan, ip )
1367 ! ** allow for slight imperfections in
1368 ! ** computation of cosine
1370 if ( xmu(i).lt.-1.00001 .or. xmu(i).gt.1.00001 ) &
1371 call wrtbad( 'xmu', inperr )
1374 do 22 i = 1, ( numang + 1 ) / 2
1375 if ( xmu(i).lt.-0.00001 .or. xmu(i).gt.1.00001 ) &
1376 call wrtbad( 'xmu', inperr )
1381 call errmsg( 'miev0--input error(s). aborting...', .true. )
1383 if ( xx.gt.20000.0 .or. dble(crefin).gt.10.0 .or. &
1384 dabs( dimag(crefin) ).gt.10.0 ) call errmsg( &
1385 'miev0--xx or crefin outside tested range', .false. )
1388 end subroutine ckinmi
1389 !***********************************************************************
1390 subroutine lpcoef ( ntrm, nmom, ipolzn, momdim, calcmo, npquan, &
1393 ! calculate legendre polynomial expansion coefficients (also
1394 ! called moments) for phase quantities ( ref. 5 formulation )
1396 ! input: ntrm number terms in mie series
1397 ! nmom, ipolzn, momdim 'miev0' arguments
1398 ! calcmo flags calculated from -ipolzn-
1399 ! npquan defined in 'miev0'
1400 ! a, b mie series coefficients
1402 ! output: pmom legendre moments ('miev0' argument)
1406 ! (1) eqs. 2-5 are in error in dave, appl. opt. 9,
1407 ! 1888 (1970). eq. 2 refers to m1, not m2; eq. 3 refers to
1408 ! m2, not m1. in eqs. 4 and 5, the subscripts on the second
1409 ! term in square brackets should be interchanged.
1411 ! (2) the general-case logic in this subroutine works correctly
1412 ! in the two-term mie series case, but subroutine 'lpco2t'
1413 ! is called instead, for speed.
1415 ! (3) subroutine 'lpco1t', to do the one-term case, is never
1416 ! called within the context of 'miev0', but is included for
1417 ! complete generality.
1419 ! (4) some improvement in speed is obtainable by combining the
1420 ! 310- and 410-loops, if moments for both the third and fourth
1421 ! phase quantities are desired, because the third phase quantity
1422 ! is the real part of a complex series, while the fourth phase
1423 ! quantity is the imaginary part of that very same series. but
1424 ! most users are not interested in the fourth phase quantity,
1425 ! which is related to circular polarization, so the present
1426 ! scheme is usually more efficient.
1430 integer ipolzn, momdim, nmom, ntrm, npquan
1431 real*8 pmom( 0:momdim, * )
1432 complex*16 a(*), b(*)
1434 ! ** specification of local variables
1436 ! am(m) numerical coefficients a-sub-m-super-l
1437 ! in dave, eqs. 1-15, as simplified in ref. 5.
1439 ! bi(i) numerical coefficients b-sub-i-super-l
1440 ! in dave, eqs. 1-15, as simplified in ref. 5.
1442 ! bidel(i) 1/2 bi(i) times factor capital-del in dave
1444 ! cm,dm() arrays c and d in dave, eqs. 16-17 (mueller form),
1445 ! calculated using recurrence derived in ref. 5
1447 ! cs,ds() arrays c and d in ref. 4, eqs. a5-a6 (sekera form),
1448 ! calculated using recurrence derived in ref. 5
1450 ! c,d() either -cm,dm- or -cs,ds-, depending on -ipolzn-
1452 ! evenl true for even-numbered moments; false otherwise
1454 ! idel 1 + little-del in dave
1456 ! maxtrm max. no. of terms in mie series
1458 ! maxmom max. no. of non-zero moments
1460 ! nummom number of non-zero moments
1464 integer maxtrm,maxmom,mxmom2,maxrcp
1465 parameter ( maxtrm = 1102, maxmom = 2*maxtrm, mxmom2 = maxmom/2, &
1466 maxrcp = 4*maxtrm + 2 )
1467 real*8 am( 0:maxtrm ), bi( 0:mxmom2 ), bidel( 0:mxmom2 ), &
1469 complex*16 cm( maxtrm ), dm( maxtrm ), cs( maxtrm ), ds( maxtrm ), &
1470 c( maxtrm ), d( maxtrm )
1471 integer k,j,l,nummom,ld2,idel,m,i,mmax,imax
1473 equivalence ( c, cm ), ( d, dm )
1474 logical pass1, evenl
1476 data pass1 / .true. /
1482 recip( k ) = 1.0 / k
1488 do 5 j = 1, max0( 1, npquan )
1493 if ( ntrm.eq.1 ) then
1494 call lpco1t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1496 else if ( ntrm.eq.2 ) then
1497 call lpco2t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1501 if ( ntrm+2 .gt. maxtrm ) &
1502 call errmsg( 'lpcoef--parameter maxtrm too small', .true. )
1504 ! ** calculate mueller c, d arrays
1505 cm( ntrm+2 ) = ( 0., 0. )
1506 dm( ntrm+2 ) = ( 0., 0. )
1507 cm( ntrm+1 ) = ( 1. - recip( ntrm+1 ) ) * b( ntrm )
1508 dm( ntrm+1 ) = ( 1. - recip( ntrm+1 ) ) * a( ntrm )
1509 cm( ntrm ) = ( recip(ntrm) + recip(ntrm+1) ) * a( ntrm ) &
1510 + ( 1. - recip(ntrm) ) * b( ntrm-1 )
1511 dm( ntrm ) = ( recip(ntrm) + recip(ntrm+1) ) * b( ntrm ) &
1512 + ( 1. - recip(ntrm) ) * a( ntrm-1 )
1514 do 10 k = ntrm-1, 2, -1
1515 cm( k ) = cm( k+2 ) - ( 1. + recip(k+1) ) * b( k+1 ) &
1516 + ( recip(k) + recip(k+1) ) * a( k ) &
1517 + ( 1. - recip(k) ) * b( k-1 )
1518 dm( k ) = dm( k+2 ) - ( 1. + recip(k+1) ) * a( k+1 ) &
1519 + ( recip(k) + recip(k+1) ) * b( k ) &
1520 + ( 1. - recip(k) ) * a( k-1 )
1522 cm( 1 ) = cm( 3 ) + 1.5 * ( a( 1 ) - b( 2 ) )
1523 dm( 1 ) = dm( 3 ) + 1.5 * ( b( 1 ) - a( 2 ) )
1525 if ( ipolzn.ge.0 ) then
1527 do 20 k = 1, ntrm + 2
1528 c( k ) = ( 2*k - 1 ) * cm( k )
1529 d( k ) = ( 2*k - 1 ) * dm( k )
1533 ! ** compute sekera c and d arrays
1534 cs( ntrm+2 ) = ( 0., 0. )
1535 ds( ntrm+2 ) = ( 0., 0. )
1536 cs( ntrm+1 ) = ( 0., 0. )
1537 ds( ntrm+1 ) = ( 0., 0. )
1539 do 30 k = ntrm, 1, -1
1540 cs( k ) = cs( k+2 ) + ( 2*k + 1 ) * ( cm( k+1 ) - b( k ) )
1541 ds( k ) = ds( k+2 ) + ( 2*k + 1 ) * ( dm( k+1 ) - a( k ) )
1544 do 40 k = 1, ntrm + 2
1545 c( k ) = ( 2*k - 1 ) * cs( k )
1546 d( k ) = ( 2*k - 1 ) * ds( k )
1552 if( ipolzn.lt.0 ) nummom = min0( nmom, 2*ntrm - 2 )
1553 if( ipolzn.ge.0 ) nummom = min0( nmom, 2*ntrm )
1554 if ( nummom .gt. maxmom ) &
1555 call errmsg( 'lpcoef--parameter maxtrm too small', .true. )
1557 ! ** loop over moments
1558 do 500 l = 0, nummom
1560 evenl = mod( l,2 ) .eq. 0
1561 ! ** calculate numerical coefficients
1562 ! ** a-sub-m and b-sub-i in dave
1563 ! ** double-sums for moments
1568 am( m ) = 2.0 * recip( 2*m + 1 )
1572 else if( evenl ) then
1576 am( m ) = ( 1. + recip( 2*m-l+1 ) ) * am( m )
1579 bi( i ) = ( 1. - recip( l-2*i ) ) * bi( i )
1581 bi( ld2 ) = ( 2. - recip( l ) ) * bi( ld2-1 )
1587 am( m ) = ( 1. - recip( 2*m+l+2 ) ) * am( m )
1590 bi( i ) = ( 1. - recip( l+2*i+1 ) ) * bi( i )
1594 ! ** establish upper limits for sums
1595 ! ** and incorporate factor capital-
1596 ! ** del into b-sub-i
1598 if( ipolzn.ge.0 ) mmax = mmax + 1
1599 imax = min0( ld2, mmax - ld2 )
1600 if( imax.lt.0 ) go to 600
1602 bidel( i ) = bi( i )
1604 if( evenl ) bidel( 0 ) = 0.5 * bidel( 0 )
1606 ! ** perform double sums just for
1607 ! ** phase quantities desired by user
1608 if( ipolzn.eq.0 ) then
1611 ! ** vectorizable loop (cray)
1613 do 100 m = ld2, mmax - i
1614 thesum = thesum + am( m ) * &
1615 ( dble( c(m-i+1) * dconjg( c(m+i+idel) ) ) &
1616 + dble( d(m-i+1) * dconjg( d(m+i+idel) ) ) )
1618 pmom( l,1 ) = pmom( l,1 ) + bidel( i ) * thesum
1620 pmom( l,1 ) = 0.5 * pmom( l,1 )
1625 if ( calcmo(1) ) then
1627 ! ** vectorizable loop (cray)
1629 do 150 m = ld2, mmax - i
1630 thesum = thesum + am( m ) * &
1631 dble( c(m-i+1) * dconjg( c(m+i+idel) ) )
1633 pmom( l,1 ) = pmom( l,1 ) + bidel( i ) * thesum
1638 if ( calcmo(2) ) then
1640 ! ** vectorizable loop (cray)
1642 do 200 m = ld2, mmax - i
1643 thesum = thesum + am( m ) * &
1644 dble( d(m-i+1) * dconjg( d(m+i+idel) ) )
1646 pmom( l,2 ) = pmom( l,2 ) + bidel( i ) * thesum
1651 if ( calcmo(3) ) then
1653 ! ** vectorizable loop (cray)
1655 do 300 m = ld2, mmax - i
1656 thesum = thesum + am( m ) * &
1657 ( dble( c(m-i+1) * dconjg( d(m+i+idel) ) ) &
1658 + dble( c(m+i+idel) * dconjg( d(m-i+1) ) ) )
1660 pmom( l,3 ) = pmom( l,3 ) + bidel( i ) * thesum
1662 pmom( l,3 ) = 0.5 * pmom( l,3 )
1666 if ( calcmo(4) ) then
1668 ! ** vectorizable loop (cray)
1670 do 400 m = ld2, mmax - i
1671 thesum = thesum + am( m ) * &
1672 ( dimag( c(m-i+1) * dconjg( d(m+i+idel) ) ) &
1673 + dimag( c(m+i+idel) * dconjg( d(m-i+1) ) ))
1675 pmom( l,4 ) = pmom( l,4 ) + bidel( i ) * thesum
1677 pmom( l,4 ) = - 0.5 * pmom( l,4 )
1684 end subroutine lpcoef
1685 !*********************************************************************
1686 subroutine lpco1t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1688 ! calculate legendre polynomial expansion coefficients (also
1689 ! called moments) for phase quantities in special case where
1690 ! no. terms in mie series = 1
1692 ! input: nmom, ipolzn, momdim 'miev0' arguments
1693 ! calcmo flags calculated from -ipolzn-
1694 ! a(1), b(1) mie series coefficients
1696 ! output: pmom legendre moments
1700 integer ipolzn, momdim, nmom,nummom,l
1701 real*8 pmom( 0:momdim, * ),sq,a1sq,b1sq
1702 complex*16 a(*), b(*), ctmp, a1b1c
1703 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
1708 a1b1c = a(1) * dconjg( b(1) )
1710 if( ipolzn.lt.0 ) then
1712 if( calcmo(1) ) pmom( 0,1 ) = 2.25 * b1sq
1713 if( calcmo(2) ) pmom( 0,2 ) = 2.25 * a1sq
1714 if( calcmo(3) ) pmom( 0,3 ) = 2.25 * dble( a1b1c )
1715 if( calcmo(4) ) pmom( 0,4 ) = 2.25 *dimag( a1b1c )
1719 nummom = min0( nmom, 2 )
1720 ! ** loop over moments
1721 do 100 l = 0, nummom
1723 if( ipolzn.eq.0 ) then
1724 if( l.eq.0 ) pmom( l,1 ) = 1.5 * ( a1sq + b1sq )
1725 if( l.eq.1 ) pmom( l,1 ) = 1.5 * dble( a1b1c )
1726 if( l.eq.2 ) pmom( l,1 ) = 0.15 * ( a1sq + b1sq )
1730 if( calcmo(1) ) then
1731 if( l.eq.0 ) pmom( l,1 ) = 2.25 * ( a1sq + b1sq / 3. )
1732 if( l.eq.1 ) pmom( l,1 ) = 1.5 * dble( a1b1c )
1733 if( l.eq.2 ) pmom( l,1 ) = 0.3 * b1sq
1736 if( calcmo(2) ) then
1737 if( l.eq.0 ) pmom( l,2 ) = 2.25 * ( b1sq + a1sq / 3. )
1738 if( l.eq.1 ) pmom( l,2 ) = 1.5 * dble( a1b1c )
1739 if( l.eq.2 ) pmom( l,2 ) = 0.3 * a1sq
1742 if( calcmo(3) ) then
1743 if( l.eq.0 ) pmom( l,3 ) = 3.0 * dble( a1b1c )
1744 if( l.eq.1 ) pmom( l,3 ) = 0.75 * ( a1sq + b1sq )
1745 if( l.eq.2 ) pmom( l,3 ) = 0.3 * dble( a1b1c )
1748 if( calcmo(4) ) then
1749 if( l.eq.0 ) pmom( l,4 ) = - 1.5 * dimag( a1b1c )
1750 if( l.eq.1 ) pmom( l,4 ) = 0.0
1751 if( l.eq.2 ) pmom( l,4 ) = 0.3 * dimag( a1b1c )
1759 end subroutine lpco1t
1760 !********************************************************************
1761 subroutine lpco2t ( nmom, ipolzn, momdim, calcmo, a, b, pmom )
1763 ! calculate legendre polynomial expansion coefficients (also
1764 ! called moments) for phase quantities in special case where
1765 ! no. terms in mie series = 2
1767 ! input: nmom, ipolzn, momdim 'miev0' arguments
1768 ! calcmo flags calculated from -ipolzn-
1769 ! a(1-2), b(1-2) mie series coefficients
1771 ! output: pmom legendre moments
1775 integer ipolzn, momdim, nmom,l,nummom
1776 real*8 pmom( 0:momdim, * ),sq,pm1,pm2,a2sq,b2sq
1777 complex*16 a(*), b(*)
1778 complex*16 a2c, b2c, ctmp, ca, cac, cat, cb, cbc, cbt, cg, ch
1779 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
1782 ca = 3. * a(1) - 5. * b(2)
1783 cat= 3. * b(1) - 5. * a(2)
1787 a2c = dconjg( a(2) )
1788 b2c = dconjg( b(2) )
1790 if( ipolzn.lt.0 ) then
1791 ! ** loop over sekera moments
1792 nummom = min0( nmom, 2 )
1795 if( calcmo(1) ) then
1796 if( l.eq.0 ) pmom( l,1 ) = 0.25 * ( sq(cat) + &
1798 if( l.eq.1 ) pmom( l,1 ) = (5./3.) * dble( cat * b2c )
1799 if( l.eq.2 ) pmom( l,1 ) = (10./3.) * b2sq
1802 if( calcmo(2) ) then
1803 if( l.eq.0 ) pmom( l,2 ) = 0.25 * ( sq(ca) + &
1805 if( l.eq.1 ) pmom( l,2 ) = (5./3.) * dble( ca * a2c )
1806 if( l.eq.2 ) pmom( l,2 ) = (10./3.) * a2sq
1809 if( calcmo(3) ) then
1810 if( l.eq.0 ) pmom( l,3 ) = 0.25 * dble( cat*cac + &
1811 (100./3.)*b(2)*a2c )
1812 if( l.eq.1 ) pmom( l,3 ) = 5./6. * dble( b(2)*cac + &
1814 if( l.eq.2 ) pmom( l,3 ) = 10./3. * dble( b(2) * a2c )
1817 if( calcmo(4) ) then
1818 if( l.eq.0 ) pmom( l,4 ) = -0.25 * dimag( cat*cac + &
1819 (100./3.)*b(2)*a2c )
1820 if( l.eq.1 ) pmom( l,4 ) = -5./6. * dimag( b(2)*cac + &
1822 if( l.eq.2 ) pmom( l,4 ) = -10./3. * dimag( b(2) * a2c )
1829 cb = 3. * b(1) + 5. * a(2)
1830 cbt= 3. * a(1) + 5. * b(2)
1832 cg = ( cbc*cbt + 10.*( cac*a(2) + b2c*cat) ) / 3.
1833 ch = 2.*( cbc*a(2) + b2c*cbt )
1835 ! ** loop over mueller moments
1836 nummom = min0( nmom, 4 )
1837 do 100 l = 0, nummom
1839 if( ipolzn.eq.0 .or. calcmo(1) ) then
1840 if( l.eq.0 ) pm1 = 0.25 * sq(ca) + sq(cb) / 12. &
1841 + (5./3.) * dble(ca*b2c) + 5.*b2sq
1842 if( l.eq.1 ) pm1 = dble( cb * ( cac/6. + b2c ) )
1843 if( l.eq.2 ) pm1 = sq(cb)/30. + (20./7.) * b2sq &
1844 + (2./3.) * dble( ca * b2c )
1845 if( l.eq.3 ) pm1 = (2./7.) * dble( cb * b2c )
1846 if( l.eq.4 ) pm1 = (40./63.) * b2sq
1847 if ( calcmo(1) ) pmom( l,1 ) = pm1
1850 if( ipolzn.eq.0 .or. calcmo(2) ) then
1851 if( l.eq.0 ) pm2 = 0.25*sq(cat) + sq(cbt) / 12. &
1852 + (5./3.) * dble(cat*a2c) + 5.*a2sq
1853 if( l.eq.1 ) pm2 = dble( cbt * ( dconjg(cat)/6. + a2c) )
1854 if( l.eq.2 ) pm2 = sq(cbt)/30. + (20./7.) * a2sq &
1855 + (2./3.) * dble( cat * a2c )
1856 if( l.eq.3 ) pm2 = (2./7.) * dble( cbt * a2c )
1857 if( l.eq.4 ) pm2 = (40./63.) * a2sq
1858 if ( calcmo(2) ) pmom( l,2 ) = pm2
1861 if( ipolzn.eq.0 ) then
1862 pmom( l,1 ) = 0.5 * ( pm1 + pm2 )
1866 if( calcmo(3) ) then
1867 if( l.eq.0 ) pmom( l,3 ) = 0.25 * dble( cac*cat + cg + &
1869 if( l.eq.1 ) pmom( l,3 ) = dble( cac*cbt + cbc*cat + &
1871 if( l.eq.2 ) pmom( l,3 ) = 0.1 * dble( cg + (200./7.) * &
1873 if( l.eq.3 ) pmom( l,3 ) = dble( ch ) / 14.
1874 if( l.eq.4 ) pmom( l,3 ) = 40./63. * dble( b2c * a(2) )
1877 if( calcmo(4) ) then
1878 if( l.eq.0 ) pmom( l,4 ) = 0.25 * dimag( cac*cat + cg + &
1880 if( l.eq.1 ) pmom( l,4 ) = dimag( cac*cbt + cbc*cat + &
1882 if( l.eq.2 ) pmom( l,4 ) = 0.1 * dimag( cg + (200./7.) * &
1884 if( l.eq.3 ) pmom( l,4 ) = dimag( ch ) / 14.
1885 if( l.eq.4 ) pmom( l,4 ) = 40./63. * dimag( b2c * a(2) )
1893 end subroutine lpco2t
1894 !*********************************************************************
1895 subroutine biga( cior, xx, ntrm, noabs, yesang, rbiga, cbiga )
1897 ! calculate logarithmic derivatives of j-bessel-function
1899 ! input : cior, xx, ntrm, noabs, yesang (defined in 'miev0')
1901 ! output : rbiga or cbiga (defined in 'miev0')
1903 ! internal variables :
1905 ! confra value of lentz continued fraction for -cbiga(ntrm)-,
1906 ! used to initialize downward recurrence.
1907 ! down = true, use down-recurrence. false, do not.
1908 ! f1,f2,f3 arithmetic statement functions used in determining
1909 ! whether to use up- or down-recurrence
1910 ! ( ref. 2, eqs. 6-8 )
1911 ! mre real refractive index
1912 ! mim imaginary refractive index
1913 ! rezinv 1 / ( mre * xx ); temporary variable for recurrence
1914 ! zinv 1 / ( cior * xx ); temporary variable for recurrence
1917 logical down, noabs, yesang
1919 real*8 mre, mim, rbiga(*), xx, rezinv, rtmp, f1,f2,f3
1920 ! complex*16 cior, ctmp, confra, cbiga(*), zinv
1921 complex*16 cior, ctmp, cbiga(*), zinv
1922 f1( mre ) = - 8.0 + mre**2 * ( 26.22 + mre * ( - 0.4474 &
1923 + mre**3 * ( 0.00204 - 0.000175 * mre ) ) )
1924 f2( mre ) = 3.9 + mre * ( - 10.8 + 13.78 * mre )
1925 f3( mre ) = - 15.04 + mre * ( 8.42 + 16.35 * mre )
1927 ! ** decide whether 'biga' can be
1928 ! ** calculated by up-recurrence
1930 mim = dabs( dimag( cior ) )
1931 if ( mre.lt.1.0 .or. mre.gt.10.0 .or. mim.gt.10.0 ) then
1933 else if ( yesang ) then
1935 if ( mim*xx .lt. f2( mre ) ) down = .false.
1938 if ( mim*xx .lt. f1( mre ) ) down = .false.
1941 zinv = 1.0 / ( cior * xx )
1942 rezinv = 1.0 / ( mre * xx )
1945 ! ** compute initial high-order 'biga' using
1946 ! ** lentz method ( ref. 1, pp. 17-20 )
1948 ctmp = confra( ntrm, zinv, xx )
1950 ! *** downward recurrence for 'biga'
1951 ! *** ( ref. 1, eq. 22 )
1953 ! ** no-absorption case
1954 rbiga( ntrm ) = dble( ctmp )
1955 do 25 n = ntrm, 2, - 1
1956 rbiga( n-1 ) = (n*rezinv) &
1957 - 1.0 / ( (n*rezinv) + rbiga( n ) )
1961 ! ** absorptive case
1962 cbiga( ntrm ) = ctmp
1963 do 30 n = ntrm, 2, - 1
1964 cbiga( n-1 ) = (n*zinv) - 1.0 / ( (n*zinv) + cbiga( n ) )
1970 ! *** upward recurrence for 'biga'
1971 ! *** ( ref. 1, eqs. 20-21 )
1973 ! ** no-absorption case
1974 rtmp = dsin( mre*xx )
1975 rbiga( 1 ) = - rezinv &
1976 + rtmp / ( rtmp*rezinv - dcos( mre*xx ) )
1978 rbiga( n ) = - ( n*rezinv ) &
1979 + 1.0 / ( ( n*rezinv ) - rbiga( n-1 ) )
1983 ! ** absorptive case
1984 ctmp = cdexp( - dcmplx(0.d0,2.d0) * cior * xx )
1985 cbiga( 1 ) = - zinv + (1.-ctmp) / ( zinv * (1.-ctmp) - &
1986 dcmplx(0.d0,1.d0)*(1.+ctmp) )
1988 cbiga( n ) = - (n*zinv) + 1.0 / ((n*zinv) - cbiga( n-1 ))
1996 !**********************************************************************
1997 complex*16 function confra( n, zinv, xx )
1999 ! compute bessel function ratio capital-a-sub-n from its
2000 ! continued fraction using lentz method ( ref. 1, pp. 17-20 )
2002 ! zinv = reciprocal of argument of capital-a
2004 ! i n t e r n a l v a r i a b l e s
2005 ! ------------------------------------
2007 ! cak term in continued fraction expansion of capital-a
2008 ! ( ref. 1, eq. 25 )
2009 ! capt factor used in lentz iteration for capital-a
2010 ! ( ref. 1, eq. 27 )
2011 ! cdenom denominator in -capt- ( ref. 1, eq. 28b )
2012 ! cnumer numerator in -capt- ( ref. 1, eq. 28a )
2013 ! cdtd product of two successive denominators of -capt-
2014 ! factors ( ref. 1, eq. 34c )
2015 ! cntn product of two successive numerators of -capt-
2016 ! factors ( ref. 1, eq. 34b )
2017 ! eps1 ill-conditioning criterion
2018 ! eps2 convergence criterion
2019 ! kk subscript k of -cak- ( ref. 1, eq. 25b )
2020 ! kount iteration counter ( used only to prevent runaway )
2021 ! maxit max. allowed no. of iterations
2022 ! mm + 1 and - 1, alternately
2025 integer n,maxit,mm,kk,kount
2028 complex*16 cak, capt, cdenom, cdtd, cnumer, cntn
2029 ! data eps1 / 1.e - 2 /, eps2 / 1.e - 8 /
2030 data eps1 / 1.d-2 /, eps2 / 1.d-8 /
2031 data maxit / 10000 /
2033 ! *** ref. 1, eqs. 25a, 27
2034 confra = ( n + 1 ) * zinv
2037 cak = ( mm * kk ) * zinv
2039 cnumer = cdenom + 1.0 / confra
2042 20 kount = kount + 1
2043 if ( kount.gt.maxit ) &
2044 call errmsg( 'confra--iteration failed to converge$', .true.)
2046 ! *** ref. 2, eq. 25b
2049 cak = ( mm * kk ) * zinv
2050 ! *** ref. 2, eq. 32
2051 if ( cdabs( cnumer/cak ).le.eps1 &
2052 .or. cdabs( cdenom/cak ).le.eps1 ) then
2054 ! ** ill-conditioned case -- stride
2055 ! ** two terms instead of one
2057 ! *** ref. 2, eqs. 34
2058 cntn = cak * cnumer + 1.0
2059 cdtd = cak * cdenom + 1.0
2060 confra = ( cntn / cdtd ) * confra
2061 ! *** ref. 2, eq. 25b
2064 cak = ( mm * kk ) * zinv
2065 ! *** ref. 2, eqs. 35
2066 cnumer = cak + cnumer / cntn
2067 cdenom = cak + cdenom / cdtd
2072 ! ** well-conditioned case
2074 ! *** ref. 2, eqs. 26, 27
2075 capt = cnumer / cdenom
2076 confra = capt * confra
2077 ! ** check for convergence
2078 ! ** ( ref. 2, eq. 31 )
2080 if ( dabs( dble(capt) - 1.0 ).ge.eps2 &
2081 .or. dabs( dimag(capt) ) .ge.eps2 ) then
2083 ! *** ref. 2, eqs. 30a-b
2084 cnumer = cak + 1.0 / cnumer
2085 cdenom = cak + 1.0 / cdenom
2093 !********************************************************************
2094 subroutine miprnt( prnt, xx, perfct, crefin, numang, xmu, &
2095 qext, qsca, gqsc, nmom, ipolzn, momdim, &
2096 calcmo, pmom, sforw, sback, tforw, tback, &
2099 ! print scattering quantities of a single particle
2102 logical perfct, prnt(*), calcmo(*)
2103 integer ipolzn, momdim, nmom, numang,i,m,j
2104 real*8 gqsc, pmom( 0:momdim, * ), qext, qsca, xx, xmu(*)
2105 real*8 fi1,fi2,fnorm
2106 complex*16 crefin, sforw, sback, tforw(*), tback(*), s1(*), s2(*)
2110 if ( perfct ) write ( *, '(''1'',10x,a,1p,e11.4)' ) &
2111 'perfectly conducting case, size parameter =', xx
2112 if ( .not.perfct ) write ( *, '(''1'',10x,3(a,1p,e11.4))' ) &
2113 'refractive index: real ', dble(crefin), &
2114 ' imag ', dimag(crefin), ', size parameter =', xx
2116 if ( prnt(1) .and. numang.gt.0 ) then
2118 write ( *, '(/,a)' ) &
2119 ' cos(angle) ------- s1 --------- ------- s2 ---------'// &
2120 ' --- s1*conjg(s2) --- i1=s1**2 i2=s2**2 (i1+i2)/2'// &
2123 fi1 = dble( s1(i) ) **2 + dimag( s1(i) )**2
2124 fi2 = dble( s2(i) ) **2 + dimag( s2(i) )**2
2125 write( *, '( i4, f10.6, 1p,10e11.3 )' ) &
2126 i, xmu(i), s1(i), s2(i), s1(i)*dconjg(s2(i)), &
2127 fi1, fi2, 0.5*(fi1+fi2), (fi2-fi1)/(fi2+fi1)
2135 write ( *, '(/,a,9x,a,17x,a,17x,a,/,(0p,f7.2, 1p,6e12.3) )' ) &
2136 ' angle', 's-sub-1', 't-sub-1', 't-sub-2', &
2137 0.0, sforw, tforw(1), tforw(2), &
2138 180., sback, tback(1), tback(2)
2139 write ( *, '(/,4(a,1p,e11.4))' ) &
2140 ' efficiency factors, extinction:', qext, &
2141 ' scattering:', qsca, &
2142 ' absorption:', qext-qsca, &
2143 ' rad. pressure:', qext-gqsc
2145 if ( nmom.gt.0 ) then
2147 write( *, '(/,a)' ) ' normalized moments of :'
2148 if ( ipolzn.eq.0 ) write ( *, '(''+'',27x,a)' ) 'phase fcn'
2149 if ( ipolzn.gt.0 ) write ( *, '(''+'',33x,a)' ) &
2151 if ( ipolzn.lt.0 ) write ( *, '(''+'',33x,a)' ) &
2154 fnorm = 4. / ( xx**2 * qsca )
2156 write ( *, '(a,i4)' ) ' moment no.', m
2158 if( calcmo(j) ) then
2159 write( fmt, 98 ) 24 + (j-1)*13
2160 write ( *,fmt ) fnorm * pmom(m,j)
2169 98 format( '( ''+'', t', i2, ', 1p,e13.4 )' )
2170 end subroutine miprnt
2171 !**************************************************************************
2172 subroutine small1 ( xx, numang, xmu, qext, qsca, gqsc, sforw, &
2173 sback, s1, s2, tforw, tback, a, b )
2175 ! small-particle limit of mie quantities in totally reflecting
2176 ! limit ( mie series truncated after 2 terms )
2178 ! a,b first two mie coefficients, with numerator and
2179 ! denominator expanded in powers of -xx- ( a factor
2180 ! of xx**3 is missing but is restored before return
2181 ! to calling program ) ( ref. 2, p. 1508 )
2185 real*8 gqsc, qext, qsca, xx, xmu(*)
2186 real*8 twothr,fivthr,fivnin,sq,rtmp
2187 complex*16 a( 2 ), b( 2 ), sforw, sback, s1(*), s2(*), &
2190 parameter ( twothr = 2./3., fivthr = 5./3., fivnin = 5./9. )
2192 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
2195 a( 1 ) = dcmplx ( 0.d0, twothr * ( 1. - 0.2 * xx**2 ) ) &
2196 / dcmplx ( 1.d0 - 0.5 * xx**2, twothr * xx**3 )
2198 b( 1 ) = dcmplx ( 0.d0, - ( 1. - 0.1 * xx**2 ) / 3. ) &
2199 / dcmplx ( 1.d0 + 0.5 * xx**2, - xx**3 / 3. )
2201 a( 2 ) = dcmplx ( 0.d0, xx**2 / 30. )
2202 b( 2 ) = dcmplx ( 0.d0, - xx**2 / 45. )
2204 qsca = 6. * xx**4 * ( sq( a(1) ) + sq( b(1) ) &
2205 + fivthr * ( sq( a(2) ) + sq( b(2) ) ) )
2207 gqsc = 6. * xx**4 * dble( a(1) * dconjg( a(2) + b(1) ) &
2208 + ( b(1) + fivnin * a(2) ) * dconjg( b(2) ) )
2211 sforw = rtmp * ( a(1) + b(1) + fivthr * ( a(2) + b(2) ) )
2212 sback = rtmp * ( a(1) - b(1) - fivthr * ( a(2) - b(2) ) )
2213 tforw( 1 ) = rtmp * ( b(1) + fivthr * ( 2.*b(2) - a(2) ) )
2214 tforw( 2 ) = rtmp * ( a(1) + fivthr * ( 2.*a(2) - b(2) ) )
2215 tback( 1 ) = rtmp * ( b(1) - fivthr * ( 2.*b(2) + a(2) ) )
2216 tback( 2 ) = rtmp * ( a(1) - fivthr * ( 2.*a(2) + b(2) ) )
2219 s1( j ) = rtmp * ( a(1) + b(1) * xmu(j) + fivthr * &
2220 ( a(2) * xmu(j) + b(2) * ( 2.*xmu(j)**2 - 1. )) )
2221 s2( j ) = rtmp * ( b(1) + a(1) * xmu(j) + fivthr * &
2222 ( b(2) * xmu(j) + a(2) * ( 2.*xmu(j)**2 - 1. )) )
2224 ! ** recover actual mie coefficients
2225 a( 1 ) = xx**3 * a( 1 )
2226 a( 2 ) = xx**3 * a( 2 )
2227 b( 1 ) = xx**3 * b( 1 )
2228 b( 2 ) = xx**3 * b( 2 )
2231 end subroutine small1
2232 !*************************************************************************
2233 subroutine small2 ( xx, cior, calcqe, numang, xmu, qext, qsca, &
2234 gqsc, sforw, sback, s1, s2, tforw, tback, &
2237 ! small-particle limit of mie quantities for general refractive
2238 ! index ( mie series truncated after 2 terms )
2240 ! a,b first two mie coefficients, with numerator and
2241 ! denominator expanded in powers of -xx- ( a factor
2242 ! of xx**3 is missing but is restored before return
2243 ! to calling program ) ( ref. 2, p. 1508 )
2245 ! ciorsq square of refractive index
2250 real*8 gqsc, qext, qsca, xx, xmu(*)
2251 real*8 twothr,fivthr,sq,rtmp
2252 complex*16 a( 2 ), b( 2 ), cior, sforw, sback, s1(*), s2(*), &
2255 parameter ( twothr = 2./3., fivthr = 5./3. )
2256 complex*16 ctmp, ciorsq
2257 sq( ctmp ) = dble( ctmp )**2 + dimag( ctmp )**2
2261 ctmp = dcmplx( 0.d0, twothr ) * ( ciorsq - 1.0 )
2262 a(1) = ctmp * ( 1.0 - 0.1 * xx**2 + (ciorsq/350. + 1./280.)*xx**4) &
2263 / ( ciorsq + 2.0 + ( 1.0 - 0.7 * ciorsq ) * xx**2 &
2264 - ( ciorsq**2/175. - 0.275 * ciorsq + 0.25 ) * xx**4 &
2265 + xx**3 * ctmp * ( 1.0 - 0.1 * xx**2 ) )
2267 b(1) = (xx**2/30.) * ctmp * ( 1.0 + (ciorsq/35. - 1./14.) *xx**2 ) &
2268 / ( 1.0 - ( ciorsq/15. - 1./6. ) * xx**2 )
2270 a(2) = ( 0.1 * xx**2 ) * ctmp * ( 1.0 - xx**2 / 14. ) &
2271 / ( 2. * ciorsq + 3. - ( ciorsq/7. - 0.5 ) * xx**2 )
2273 qsca = 6. * xx**4 * ( sq(a(1)) + sq(b(1)) + fivthr * sq(a(2)) )
2274 gqsc = 6. * xx**4 * dble( a(1) * dconjg( a(2) + b(1) ) )
2276 if ( calcqe ) qext = 6. * xx * dble( a(1) + b(1) + fivthr * a(2) )
2279 sforw = rtmp * ( a(1) + b(1) + fivthr * a(2) )
2280 sback = rtmp * ( a(1) - b(1) - fivthr * a(2) )
2281 tforw( 1 ) = rtmp * ( b(1) - fivthr * a(2) )
2282 tforw( 2 ) = rtmp * ( a(1) + 2. * fivthr * a(2) )
2283 tback( 1 ) = tforw( 1 )
2284 tback( 2 ) = rtmp * ( a(1) - 2. * fivthr * a(2) )
2287 s1( j ) = rtmp * ( a(1) + ( b(1) + fivthr * a(2) ) * xmu(j) )
2288 s2( j ) = rtmp * ( b(1) + a(1) * xmu(j) + fivthr * a(2) &
2289 * ( 2. * xmu(j)**2 - 1. ) )
2291 ! ** recover actual mie coefficients
2292 a( 1 ) = xx**3 * a( 1 )
2293 a( 2 ) = xx**3 * a( 2 )
2294 b( 1 ) = xx**3 * b( 1 )
2298 end subroutine small2
2299 !***********************************************************************
2300 subroutine testmi ( qext, qsca, gqsc, sforw, sback, s1, s2, &
2301 tforw, tback, pmom, momdim, ok )
2303 ! compare mie code test case results with correct answers
2304 ! and return ok=false if even one result is inaccurate.
2306 ! the test case is : mie size parameter = 10
2307 ! refractive index = 1.5 - 0.1 i
2308 ! scattering angle = 140 degrees
2311 ! results for this case may be found among the test cases
2312 ! at the end of reference (1).
2314 ! *** note *** when running on some computers, esp. in single
2315 ! precision, the 'accur' criterion below may have to be relaxed.
2316 ! however, if 'accur' must be set larger than 10**-3 for some
2317 ! size parameters, your computer is probably not accurate
2318 ! enough to do mie computations for those size parameters.
2322 real*8 qext, qsca, gqsc, pmom( 0:momdim, * )
2323 complex*16 sforw, sback, s1(*), s2(*), tforw(*), tback(*)
2326 real*8 accur, testqe, testqs, testgq, testpm( 0:1 )
2327 complex*16 testsf, testsb,tests1,tests2,testtf(2), testtb(2)
2328 data testqe / 2.459791 /, testqs / 1.235144 /, &
2329 testgq / 1.139235 /, testsf / ( 61.49476, -3.177994 ) /, &
2330 testsb / ( 1.493434, 0.2963657 ) /, &
2331 tests1 / ( -0.1548380, -1.128972) /, &
2332 tests2 / ( 0.05669755, 0.5425681) /, &
2333 testtf / ( 12.95238, -136.6436 ), ( 48.54238, 133.4656 ) /, &
2334 testtb / ( 41.88414, -15.57833 ), ( 43.37758, -15.28196 )/, &
2335 testpm / 227.1975, 183.6898 /
2337 ! data accur / 1.e-5 /
2338 data accur / 1.e-4 /
2339 wrong( calc, exact ) = dabs( (calc - exact) / exact ) .gt. accur
2343 if ( wrong( qext,testqe ) ) &
2344 call tstbad( 'qext', abs((qext - testqe) / testqe), ok )
2345 if ( wrong( qsca,testqs ) ) &
2346 call tstbad( 'qsca', abs((qsca - testqs) / testqs), ok )
2347 if ( wrong( gqsc,testgq ) ) &
2348 call tstbad( 'gqsc', abs((gqsc - testgq) / testgq), ok )
2350 if ( wrong( dble(sforw), dble(testsf) ) .or. &
2351 wrong( dimag(sforw), dimag(testsf) ) ) &
2352 call tstbad( 'sforw', cdabs((sforw - testsf) / testsf), ok )
2354 if ( wrong( dble(sback), dble(testsb) ) .or. &
2355 wrong( dimag(sback), dimag(testsb) ) ) &
2356 call tstbad( 'sback', cdabs((sback - testsb) / testsb), ok )
2358 if ( wrong( dble(s1(1)), dble(tests1) ) .or. &
2359 wrong( dimag(s1(1)), dimag(tests1) ) ) &
2360 call tstbad( 's1', cdabs((s1(1) - tests1) / tests1), ok )
2362 if ( wrong( dble(s2(1)), dble(tests2) ) .or. &
2363 wrong( dimag(s2(1)), dimag(tests2) ) ) &
2364 call tstbad( 's2', cdabs((s2(1) - tests2) / tests2), ok )
2367 if ( wrong( dble(tforw(n)), dble(testtf(n)) ) .or. &
2368 wrong( dimag(tforw(n)), dimag(testtf(n)) ) ) &
2369 call tstbad( 'tforw', cdabs( (tforw(n) - testtf(n)) / &
2371 if ( wrong( dble(tback(n)), dble(testtb(n)) ) .or. &
2372 wrong( dimag(tback(n)), dimag(testtb(n)) ) ) &
2373 call tstbad( 'tback', cdabs( (tback(n) - testtb(n)) / &
2378 if ( wrong( pmom(m,1), testpm(m) ) ) &
2379 call tstbad( 'pmom', dabs( (pmom(m,1)-testpm(m)) / &
2385 end subroutine testmi
2386 !**************************************************************************
2387 subroutine errmsg( messag, fatal )
2389 ! print out a warning or error message; abort if error
2391 USE module_peg_util, only: peg_message, peg_error_fatal
2396 character*(*) messag
2397 integer maxmsg, nummsg
2398 save maxmsg, nummsg, once
2399 data nummsg / 0 /, maxmsg / 100 /, once / .false. /
2403 ! write ( *, '(2a)' ) ' ******* error >>>>>> ', messag
2405 write( msg, '(a)' ) &
2406 'FASTJ mie fatal error ' // &
2408 call peg_message( lunerr, msg )
2409 call peg_error_fatal( lunerr, msg )
2413 if ( nummsg.gt.maxmsg ) then
2414 ! if ( .not.once ) write ( *,99 )
2415 if ( .not.once )then
2416 write( msg, '(a)' ) &
2417 'FASTJ mie: too many warning messages -- no longer printing '
2418 call peg_message( lunerr, msg )
2422 msg = 'FASTJ mie warning ' // messag
2423 call peg_message( lunerr, msg )
2424 ! write ( *, '(2a)' ) ' ******* warning >>>>>> ', messag
2429 ! 99 format( ///,' >>>>>> too many warning messages -- ', &
2430 ! 'they will no longer be printed <<<<<<<', /// )
2431 end subroutine errmsg
2432 !********************************************************************
2433 subroutine wrtbad ( varnam, erflag )
2435 ! write names of erroneous variables
2437 ! input : varnam = name of erroneous variable to be written
2438 ! ( character, any length )
2440 ! output : erflag = logical flag, set true by this routine
2441 ! ----------------------------------------------------------------------
2442 USE module_peg_util, only: peg_message
2445 character*(*) varnam
2447 integer maxmsg, nummsg
2450 data nummsg / 0 /, maxmsg / 50 /
2454 ! write ( *, '(3a)' ) ' **** input variable ', varnam, &
2456 msg = 'FASTJ mie input variable in error ' // varnam
2457 call peg_message( lunerr, msg )
2459 if ( nummsg.eq.maxmsg ) &
2460 call errmsg ( 'too many input variable errors. aborting...$', .true. )
2463 end subroutine wrtbad
2464 !******************************************************************
2465 subroutine tstbad( varnam, relerr, ok )
2467 ! write name (-varnam-) of variable failing self-test and its
2468 ! percent error from the correct value. return ok = false.
2471 character*(*) varnam
2477 write( *, '(/,3a,1p,e11.2,a)' ) &
2478 ' output variable ', varnam,' differed by', 100.*relerr, &
2479 ' per cent from correct value. self-test failed.'
2482 end subroutine tstbad
2483 !-----------------------------------------------------------------------
2484 end module module_fastj_mie