1module multiIRbgck_mod
2 ! MODULE multiIRbgck_mod (prefix='irbg' category='1. High-level functionality')
3 !
4 !:Purpose: Variables for multispectral infrared background check and quality
5 ! control.
6 !
7 use rttovInterfaces_mod
8 use tovsNL_mod
9 use rttov_const, only : inst_id_iasi
10 use rttov_types, only : &
11 rttov_coefs ,&
12 rttov_profile ,&
13 rttov_radiance ,&
14 rttov_transmission ,&
15 rttov_chanprof ,&
16 rttov_emissivity
17 use utilities_mod
18 use obsSpaceData_mod
19 use midasMpi_mod
20 use columnData_mod
21 use MathPhysConstants_mod
22 implicit none
23 save
24 private
25 ! Public functions (methods)
26 public :: irbg_setup, irbg_bgCheckIR
27
28 integer, parameter :: nClassAVHRR = 7
29 integer, parameter :: NIR = 3, NVIS = 3
30 integer, parameter :: nChanAVHRR = NIR + NVIS
31 integer, parameter :: nmaxinst = 10
32
33 ! Cloud top units : (1) mb, (2) meters
34 ! (subroutines cloud_height (iopt1) and cloud_top (iopt2))
35
36 integer, parameter :: iopt1 = 2 ! verify subr input if iopt1 changes
37 integer, parameter :: iopt2 = 1
38
39 ! Cloud top based on which background profile matching (subroutine cloud_top)
40 ! (0) brightness temperature, (1) radiance, (2) both
41
42 integer, parameter :: ihgt = 2
43
44 ! Highest flag in post files (value of N in 2^N)
45
46 integer, parameter :: bitflag = 29
47
48 real(8),parameter :: albedoThresholdQC= 0.25d0 ! max albedo allowed over the water
49
50 real(8),parameter :: seuilalb_static(NIR,0:2)= reshape( (/ 70.0,67.0,50.0, &
51 40.0,37.0,37.0, &
52 70.0,57.0,40. /),(/3,3/) )
53 real(8),parameter :: seuilalb_homog(NIR,0:2)= reshape( (/ 15.0,18.0,13.0, &
54 9.0,10.0,10.0, &
55 18.0,16.0,10.0 /),(/3,3/) )
56 real(8) :: seuilbt_homog(NVIS+1:nChanAVHRR,0:2,1:2)= reshape( (/5.d0, 4.d0, 4.d0, 4.d0, 3.d0, 3.d0, &
57 5.d0, 4.d0, 4.d0, 5.d0, 5.d0, 5.d0, &
58 4.d0, 3.d0, 3.d0, 5.d0, 5.d0, 5.d0/), (/3,3,2/) )
59
60 ! Number of channels to use for cloud top height detection
61 ! with the "background profile matching" method (subroutine cloud_top)
62 integer, parameter :: nch_he = 4
63
64 ! Number of channels pairs to use for cloud top height detection
65 ! with the CO2-slicing method. (subroutine co2_slicing)
66 integer, parameter :: nco2 = 13
67
68 ! Namelist variables:
69 integer :: ninst ! MUST NOT BE INCLUDED IN NAMELIST!
70 character(len=7) :: inst(nmaxinst) ! List of instrument names
71 integer :: iwindow(nmaxinst) ! Ref window channel for clear/cloudy profile detection
72 integer :: iwindow_alt(nmaxinst) ! Alternate window channel for clear/cloudy profile detection
73 integer :: ilist1(nmaxinst,nch_he) ! Chan numbers for cloud top height detection: background profile matching
74 integer :: ilist2(nmaxinst,nco2) ! Chan numbers for cloud top height detection: CO2-slicing
75 integer :: ilist2_pair(nmaxinst,nco2) ! Chan number pairs for cloud top height detection: CO2-slicing
76 real(8) :: dtw ! Max delta allowed btwn guess and true skin temp over water
77 real(8) :: dtl ! Max delta allowed btwn guess and true skin temp over land
78 real(8) :: pco2min ! Min RTTOV level for lev_start variable entering CO2 slicing in mb
79 real(8) :: pco2max ! Max RTTOV level for lev_start variable entering CO2 slicing in mb
80 real(8) :: night_ang ! Min solar zenith angle for night (between 90 and 180)
81 real(8) :: crisCloudFractionThreshold ! threshold for CrIS cloud detection from VIIRS cloud mask
82
83 type(rttov_coefs) :: coefs_avhrr
84
85 type avhrr_bgck_iasi
86 real(8) :: radmoy(nClassAVHRR,nChanAVHRR)
87 real(8) :: radstd(nClassAVHRR,nChanAVHRR)
88 real(8) :: cfrac(nClassAVHRR)
89 real(8) :: tbmoy(nClassAVHRR,NVIS+1:NVIS+NIR)
90 real(8) :: tbstd(nClassAVHRR,NVIS+1:NVIS+NIR)
91 real(8) :: albedmoy(nClassAVHRR,1:NVIS)
92 real(8) :: albedstd(nClassAVHRR,1:NVIS)
93 real(8) :: tbstd_pixelIASI(NVIS+1:NVIS+NIR)
94 real(8) :: albstd_pixeliasi(1:NVIS)
95 real(8) :: radclearcalc(NVIS+1:NVIS+NIR)
96 real(8) :: tbclearcalc(NVIS+1:NVIS+NIR)
97 real(8),allocatable :: radovcalc(:,:)
98 real(8) :: transmsurf(NVIS+1:NVIS+NIR)
99 real(8) :: emiss(NVIS+1:NVIS+NIR)
100 end type avhrr_bgck_iasi
101
102 type(avhrr_bgck_iasi), allocatable :: avhrr_bgck(:) ! avhrr parameters for IASI quality control
103
104contains
105
106
107 !--------------------------------------------------------------------------
108 ! irbg_init
109 !--------------------------------------------------------------------------
110 subroutine irbg_init()
111 !
112 !:Purpose: This subroutine reads the namelist section NAMBGCKIR
113 ! for the module.
114 implicit none
115
116 ! Locals:
117 integer :: nulnam, ierr
118 logical, save :: first = .true.
119 integer, external :: fnom, fclos
120 integer :: instrumentIndex
121 namelist /NAMBGCKIR/ ninst, inst, iwindow, iwindow_alt, ilist1, ilist2, ilist2_pair
122 namelist /NAMBGCKIR/ dtw, dtl, pco2min, pco2max, night_ang, crisCloudFractionThreshold
123
124 if (first) then
125
126 ! set the default values for namelist variables
127 ninst = MPC_missingValue_INT
128 inst(:) = '*EMPTY*'
129 iwindow(:) = 0
130 iwindow_alt(:) = 0
131 ilist1(:,:) = 0
132 ilist2(:,:) = 0
133 ilist2_pair(:,:) = 0
134 dtw = 0.0d0
135 dtl = 0.0d0
136 pco2min = 0.0d0
137 pco2max = 0.0d0
138 night_ang = 0.0d0
139 crisCloudFractionThreshold = -1.d0
140
141 ! read the namelist
142 nulnam = 0
143 ierr = fnom(nulnam, './flnml','FTN+SEQ+R/O', 0)
144 read(nulnam, nml=NAMBGCKIR, iostat=ierr)
145 if (ierr /= 0) call utl_abort('irbg_init: Error reading namelist')
146 if (mmpi_myid == 0) write(*, nml=NAMBGCKIR)
147 if (ninst /= MPC_missingValue_INT) then
148 call utl_abort('irbg_init: check NAMBGCKIR namelist section: ninst should be removed')
149 end if
150 ninst = 0
151 do instrumentIndex = 1, nmaxinst
152 if (inst(instrumentIndex) == '*EMPTY*') exit
153 ninst = ninst + 1
154 end do
155 ierr = fclos(nulnam)
156 first = .false.
157
158 end if
159
160 end subroutine irbg_init
161
162 !--------------------------------------------------------------------------
163 ! irbg_setup
164 !--------------------------------------------------------------------------
165 subroutine irbg_setup()
166 !
167 !:Purpose: Memory allocation for the Hyperspectral Infrared
168 ! background check variables.
169 !
170 implicit none
171
172 ! Locals:
173 integer :: allocStatus(2)
174 integer :: tovsIndex, maxChannelNumber
175 integer :: sensorIndex, channelNumber
176
177 ! Memory allocation for background check related variables
178 allocStatus(:) = 0
179 allocate( tvs_surfaceParameters(tvs_nobtov), stat=allocStatus(1))
180 call utl_checkAllocationStatus(allocStatus(1:1), " irbg_setup tvs_surfaceParameters")
181
182 !___ emissivity by profile
183
184 maxChannelNumber = 1
185 do tovsIndex = 1, tvs_nobtov
186 sensorIndex = tvs_lsensor(tovsIndex)
187 channelNumber = tvs_nchan(sensorIndex)
188 if (channelNumber > maxChannelNumber) maxChannelNumber=channelNumber
189 end do
190
191 allocate( tvs_emissivity (maxChannelNumber,tvs_nobtov), stat=allocStatus(1))
192 call utl_checkAllocationStatus(allocStatus(1:1), " irbg_setup tvs_emissivity")
193
194 do sensorIndex = 1, tvs_nsensors
195 if ( tvs_instruments(sensorIndex) == inst_id_iasi ) then
196 allocate ( avhrr_bgck(tvs_nobtov), stat=allocStatus(1))
197 call utl_checkAllocationStatus(allocStatus(1:1), " irbg_setup avhrr_bgck")
198 exit
199 end if
200 end do
201
202 end subroutine irbg_setup
203
204 !--------------------------------------------------------------------------
205 ! irbg_bgCheckIR
206 !--------------------------------------------------------------------------
207 subroutine irbg_bgCheckIR(columnTrlOnTrlLev, obsSpaceData)
208 !
209 !:Purpose: Do background check on all hyperspectral infrared observations
210 !
211 implicit none
212
213 ! Arguments:
214 type(struct_columnData), intent(in) :: columnTrlOnTrlLev
215 type(struct_obs), intent(inout) :: obsSpaceData
216
217 ! Locals:
218 integer,allocatable :: nobir(:)
219 integer :: headerIndex, idatyp, sensorIndex, instrumentIndex
220 logical :: irDataPresent
221
222 call utl_tmg_start(115,'--BgckInfrared')
223
224 irDataPresent = .false.
225 call obs_set_current_header_list(obsSpaceData,'TO')
226 HEADER0: do
227 headerIndex = obs_getHeaderIndex(obsSpaceData)
228 if (headerIndex < 0) exit HEADER0
229 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
230 if ( tvs_isIdBurpHyperSpectral(idatyp) ) then
231 irDataPresent = .true.
232 end if
233 end do HEADER0
234
235 if ( .not. irDataPresent ) then
236 write(*,*) 'WARNING: WILL NOT RUN irbg_bgCheckIR since no IR'
237 return
238 end if
239
240 write(*,'(A)') " ****************"
241 write(*,'(A)') " BEGIN IR BACKGROUND CHECK"
242 write(*,'(A)') " **************** **************** ****************"
243
244 ! Preliminary initializations
245
246 tvs_nobtov = 0
247 call irbg_init()
248 allocate (nobir(ninst))
249 nobir = 0
250
251
252 ! Loop over all header indices of the 'TO' family
253 ! Set the header list (and start at the beginning of the list)
254 call obs_set_current_header_list(obsSpaceData,'TO')
255 HEADER: do
256 headerIndex = obs_getHeaderIndex(obsSpaceData)
257 if (headerIndex < 0) exit HEADER
258
259 idatyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
260
261 if ( .not. tvs_isIdBurpTovs(idatyp) ) then
262 write(*,*) 'irbg_bgCheckIR: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
263 cycle HEADER ! Proceed to the next header_index
264 end if
265 tvs_nobtov = tvs_nobtov + 1
266 do instrumentIndex=1, ninst
267 if ( tvs_isIdBurpInst(idatyp,inst(instrumentIndex)) ) then
268 nobir(instrumentIndex) = nobir(instrumentIndex) + 1
269 exit
270 end if
271 end do
272 end do HEADER
273
274 do instrumentIndex=1, ninst
275 if (nobir(instrumentIndex) > 0) then
276 do sensorIndex=1,tvs_nsensors
277 if (tvs_instruments(sensorIndex) == tvs_getInstrumentId(inst(instrumentIndex)) ) then
278 call irbg_doQualityControl (columnTrlOnTrlLev, obsSpaceData, inst(instrumentIndex), sensorIndex)
279 end if
280 end do
281 end if
282 end do
283 deallocate (nobir)
284
285 call utl_tmg_stop(115)
286
287 end subroutine irbg_bgCheckIR
288
289 !--------------------------------------------------------------------------
290 ! bgck_get_qcid
291 !--------------------------------------------------------------------------
292 subroutine bgck_get_qcid(instrumentName, qcid )
293 !
294 implicit none
295
296 ! Arguments:
297 character(len=*), intent(in) :: instrumentName
298 integer, intent(out) :: qcid
299
300 ! Locals:
301 integer :: i
302
303 qcid = -1
304
305 do i=1, ninst
306 if (trim(instrumentName) == trim(inst(i))) then
307 qcid = i
308 exit
309 end if
310 end do
311
312 if (qcid == -1) then
313 write(*,*) "Unknown instrument ", instrumentName
314 call utl_abort('bgck_get_qcid')
315 end if
316
317 end subroutine bgck_get_qcid
318
319 !--------------------------------------------------------------------------
320 ! irbg_doQualityControl
321 !--------------------------------------------------------------------------
322 subroutine irbg_doQualityControl (columnTrlOnTrlLev, obsSpaceData, instrumentName, id_opt)
323 !
324 !:Purpose: Quality control of hyperspectral infrared observations.
325 ! assign assimilation flags to observations
326 !
327 implicit none
328
329 ! Arguments:
330 type(struct_columnData), intent(in) :: columnTrlOnTrlLev
331 type(struct_obs), intent(inout) :: obsSpaceData
332 character(len=*), intent(in) :: instrumentName
333 integer, optional, intent(in) :: id_opt
334
335 ! Locals:
336 integer :: jc, nchn, levelIndex, bitIndex, channelNumber, classIndex
337 integer :: columnIndex
338 integer :: iwindo, iwindo_alt
339 integer :: bodyIndex, bodyStart, bodyEnd, headerIndex
340 integer :: idatyp
341 real(8) :: difftop_min
342 integer :: modelTopIndex
343 integer :: count
344 real(8) :: t_effective
345 integer :: allocStatus(27)
346 real(8) :: tg, p0, tskinRetrieved, ptop_T, qs
347 real(8), allocatable :: tt(:), height(:,:)
348 real(8), allocatable :: pressure(:,:)
349 real(8), allocatable :: btObsErr(:), btObs(:), btCalc(:), rcal_clr(:), sfctau(:)
350 real(8), allocatable :: radObs(:), cloudyRadiance(:,:), transm(:,:), emi_sfc(:)
351 real(8), allocatable :: ptop_bt(:), ptop_rd(:)
352 real(8), allocatable :: pmin(:), dtaudp1(:), maxwf(:)
353 real(8), allocatable :: cloudyRadiance_avhrr(:,:)
354 integer, allocatable :: rejflag(:,:)
355 integer, allocatable :: ntop_bt(:), ntop_rd(:)
356 integer, allocatable :: minp(:), fate(:), channelIndexes(:)
357 real(8) :: clfr, sunZenithAngle, satelliteAzimuthAngle, satelliteZenithAngle, sunAzimuthAngle
358 real(8) :: albedo, ice, pcnt_wat, pcnt_reg
359 real(8) :: ptop_eq,ptop_mb
360 real(8) :: ptop_co2(nco2),fcloud_co2(nco2)
361 real(8) :: etop,vtop,ecf,vcf,heff
362 real(8) :: tampon,cfsub
363 real(8) :: tskinRetrieved_avhrr(nClassAVHRR), sfctau_avhrr(NIR), emi_sfc_avhrr(NIR), rcal_clr_avhrr(NIR)
364 real(8) :: ptop_bt_avhrr(NIR,nClassAVHRR), ptop_rd_avhrr(NIR,nClassAVHRR)
365 real(8) :: btObs_avhrr(NIR,nClassAVHRR), radObs_avhrr(NIR,nClassAVHRR), ptop_eq_avhrr(nClassAVHRR)
366 real(8) :: cfrac_avhrr
367 real(8) :: avhrr_surfem1(NIR)
368 real(8) :: albedoThreshold(NIR)
369 integer :: ksurf,ltype
370 integer :: cldflag, lev_start
371 integer :: gncldflag
372 integer :: ichref
373 integer :: ntop_eq, ntop_mb
374 integer :: ngood
375 integer :: ntop_co2(nco2)
376 integer :: cldflag_avhrr(nClassAVHRR),lev_start_avhrr(nClassAVHRR),ichref_avhrr(nClassAVHRR),ntop_rd_avhrr(NIR,nClassAVHRR)
377 integer :: ntop_bt_avhrr(NIR,nClassAVHRR),ntop_eq_avhrr(nClassAVHRR)
378 logical :: assim_all
379 logical :: sunZenithAnglePresent
380 logical :: satelliteAzimuthAnglePresent, satelliteZenithAnglePresent, sunAzimuthAnglePresent
381 integer, parameter :: nn=2
382 integer, parameter :: ilist_avhrr(nn)=(/ 2 ,3 /)
383 integer :: countInvalidChannels
384 logical :: bad
385 real(8), parameter :: sunzenmax=87.12d0
386 real(8) :: minpavhrr(2:3)
387 real(8) :: anisot,zlamb,zcloud,scos,del,deltaphi
388 integer :: ier,ijour,iloc(2:3),co2min(1),co2max(1)
389 integer :: channelIndex,ilist_co2(nco2),ilist_co2_pair(nco2),ilist_he(nch_he)
390 integer :: nlv_T,id,sensorIndex, qcid, nchannels
391 logical :: liasi,lairs,lcris
392 type (rttov_profile), pointer :: profiles(:)
393
394 write (*,*) "Entering irbg_doQualityControl"
395
396 call tvs_getProfile(profiles, 'nl')
397
398 liasi= ( trim(instrumentName) == "IASI" .or. trim(instrumentName) == "iasi")
399 lairs= ( trim(instrumentName) == "AIRS" .or. trim(instrumentName) == "airs")
400 lcris= ( trim(instrumentName) == "CRIS" .or. trim(instrumentName) == "cris" .or. trim(instrumentName) == "CRISFSR" .or. &
401 trim(instrumentName) == "crisfsr" )
402
403 call bgck_get_qcid(instrumentName,qcid)
404
405 if (present(id_opt)) then
406 id = id_opt
407 else
408 ! Find sensor number corresponding to the desired instrument
409 id = -1
410 do sensorIndex = 1, tvs_nsensors
411 if ( trim(tvs_instrumentName(sensorIndex)) == TRIM(instrumentName)) then
412 id = sensorIndex
413 exit
414 end if
415 end do
416 if (id < 0) call utl_abort("irbg_doQualityControl: should not happen !")
417 end if
418
419 ! Find number of profiles
420 count = 0
421
422 ! Loop over all header indices of the 'TO' family
423 call obs_set_current_header_list(obsSpaceData,'TO')
424 HEADER: do
425 headerIndex = obs_getHeaderIndex(obsSpaceData)
426 if (headerIndex < 0) exit HEADER
427 if ( tvs_tovsIndex( headerIndex ) < 0) cycle HEADER
428 idatyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
429 if ( tvs_isIdBurpInst(idatyp,instrumentName) .and. tvs_lsensor(tvs_tovsIndex (headerIndex)) == id ) then
430 count = count + 1
431 end if
432 end do HEADER
433
434 if ( count == 0 ) return
435 ! Find number of channels and RTTOV levels
436
437 nchn = tvs_coefs(id) % coef % fmv_chn
438
439 nlv_T = col_getNumLev(columnTrlOnTrlLev,'TH')
440
441 write(*,*) ' irbg_doQualityControl - nchn ', nchn
442
443
444 ! information to extract (transvidage)
445 !
446 ! tg -- guess skin temperatures (deg K)
447 ! p0 -- surface pressure (hPa)
448 ! tt(nlv_T-1) -- temperature profiles on NWP model levels (deg K)
449 ! height(nlv_T-1,1) -- height profiles on NWP model levels (m)
450 ! qs -- surface specific humidity (kg/kg)
451 ! btObsErr(nchn) -- observation error standard deviation
452 ! btObs(nchn) -- observed brightness temperatures (deg K)
453 ! btCalc(nchn) -- computed brightness temperatures (deg K)
454 ! rcal_clr(nchn) -- computed clear radiances (mw/m2/sr/cm-1)
455 ! sfctau(nchn) -- surface to space transmittances (0-1)
456 ! cloudyRadiance(nchn,nlv_T-1) -- overcast cloudy radiances (mw/m2/sr/cm-1)
457 ! transm(nchn,nlv_T) -- layer to space transmittances (0-1)
458 ! emi_sfc(nchn) -- surface emissivities (0-1)
459 ! ksurf -- surface type in obs file (0, 1)
460 ! clfr -- cloud fraction (%)
461 ! sunZenithAngle -- sun zenith angle (deg)
462 ! satelliteAzimuthAngle -- satellite azimuth angle (deg)
463 ! satelliteZenithAngle -- satellite zenith angle (deg)
464 ! albedo -- surface albedo (0-1)
465 ! ice -- ice fraction (0-1)
466 ! ltype -- surface type (1,...,20)
467 ! pcnt_wat -- water fraction (0-1)
468 ! pcnt_reg -- water fraction in the area (0-1)
469 ! radObs(nchn) -- observed radiances (mW/m2/sr/cm-1)
470
471 allocStatus(:) = 0
472
473 allocate ( btObsErr(nchn), stat= allocStatus(1))
474 allocate ( btObs(nchn), stat= allocStatus(2))
475 allocate ( btCalc(nchn), stat= allocStatus(3))
476 allocate ( rcal_clr(nchn), stat= allocStatus(4))
477 allocate ( sfctau(nchn), stat= allocStatus(5))
478 allocate ( cloudyRadiance(nchn,nlv_T-1), stat= allocStatus(6))
479 allocate ( transm(nchn,nlv_T), stat= allocStatus(7))
480 allocate ( emi_sfc(nchn), stat= allocStatus(8))
481 allocate ( radObs(nchn), stat= allocStatus(11))
482 allocate ( rejflag(nchn,0:bitflag), stat= allocStatus(12))
483 allocate ( ntop_bt(nchn), stat= allocStatus(13))
484 allocate ( ntop_rd(nchn), stat= allocStatus(14))
485 allocate ( ptop_bt(nchn), stat= allocStatus(15))
486 allocate ( ptop_rd(nchn), stat= allocStatus(16))
487 allocate ( minp(nchn), stat= allocStatus(17))
488 allocate ( pmin(nchn), stat= allocStatus(18))
489 allocate ( dtaudp1(nchn), stat= allocStatus(19))
490 allocate ( fate(nchn), stat= allocStatus(20))
491 if (liasi) allocate ( cloudyRadiance_avhrr(NIR,nlv_T-1), stat= allocStatus(21))
492 allocate ( maxwf(nchn), stat= allocStatus(22))
493 allocate ( pressure(nlv_T-1,1), stat= allocStatus(24))
494 allocate ( tt(nlv_T-1), stat= allocStatus(25))
495 allocate ( height(nlv_T-1,1), stat= allocStatus(26))
496 allocate ( channelIndexes(nchn), stat= allocStatus(27))
497 call utl_checkAllocationStatus(allocStatus, " irbg_doQualityControl 1")
498
499 difftop_min = 100000.d0
500 modelTopIndex = 1
501
502 ptop_T = col_getPressure(columnTrlOnTrlLev,1,1,'TH')
503
504 write(*,*) 'TOIT DU MODELE (MB)'
505 write(*,*) 0.01d0 * ptop_T
506 write(*,*) 'NIVEAU DU MODELE DE TRANSFERT RADIATIF LE PLUS PRES DU TOIT DU MODELE'
507 write(*,*) modelTopIndex
508
509 tvs_nobtov = 0
510
511 ! Loop over all header indices of the 'TO' family
512 call obs_set_current_header_list(obsSpaceData, 'TO')
513 HEADER_2: do
514 headerIndex = obs_getHeaderIndex(obsSpaceData)
515 if (headerIndex < 0) exit HEADER_2
516
517 idatyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
518
519 if ( tvs_isIdBurpTovs(idatyp) ) tvs_nobtov = tvs_nobtov + 1
520 if ( tvs_tovsIndex(headerIndex) < 0) cycle HEADER_2
521 if ( tvs_isIdBurpInst(idatyp,instrumentName) .and. tvs_lsensor(tvs_tovsIndex (headerIndex)) == id) then
522 btObs(:) = -1.d0
523 btCalc(:) = -1.d0
524 btObsErr(:) = -1.d0
525 rcal_clr(:) = -1.d0
526 sfctau(:) = -1.d0
527 cloudyRadiance(:,:) = -1.d0
528 transm(:,:) = -1.d0
529 emi_sfc(:) = -1.d0
530 rejflag(:,:) = 0
531 channelIndexes(:) = -1
532
533 if (liasi) then
534 classIndex = 1
535 do columnIndex = OBS_CF1, OBS_CF7
536 avhrr_bgck(headerIndex)%cfrac(classIndex) = obs_headElem_r(obsSpaceData,columnIndex,headerIndex)
537 classIndex = classIndex + 1
538 end do
539 classIndex = 1
540 channelNumber = 1
541 do columnIndex = OBS_M1C1, OBS_M7C6
542 avhrr_bgck(headerIndex)%radmoy(classIndex,channelNumber) = obs_headElem_r(obsSpaceData,columnIndex,headerIndex)
543 channelNumber = channelNumber + 1
544 if (channelNumber > nChanAVHRR) then
545 channelNumber = 1
546 classIndex = classIndex + 1
547 end if
548 end do
549 classIndex = 1
550 channelNumber = 1
551 do columnIndex = OBS_S1C1, OBS_S7C6
552 avhrr_bgck(headerIndex)%radstd(classIndex,channelNumber) = obs_headElem_r(obsSpaceData,columnIndex,headerIndex)
553 channelNumber =channelNumber + 1
554 if (channelNumber> nChanAVHRR) then
555 channelNumber = 1
556 classIndex = classIndex + 1
557 end if
558 end do
559 sunAzimuthAngle = obs_headElem_r(obsSpaceData,OBS_SAZ,headerIndex)
560 sunAzimuthAnglePresent = ( abs(sunAzimuthAngle - MPC_missingValue_R8) > 0.01 )
561 end if
562
563 tg = col_getElem(columnTrlOnTrlLev, 1, headerIndex, 'TG')
564 p0 = col_getElem(columnTrlOnTrlLev, 1, headerIndex, 'P0') * MPC_MBAR_PER_PA_R8
565
566 do levelIndex = 1, nlv_T - 1
567 tt(levelIndex) = col_getElem(columnTrlOnTrlLev, levelIndex+1, headerIndex, 'TT')
568 height(levelIndex,1) = col_getHeight(columnTrlOnTrlLev, levelIndex+1, headerIndex, 'TH')
569 pressure(levelIndex,1)= col_getPressure(columnTrlOnTrlLev, levelIndex+1, headerIndex, 'TH') * MPC_MBAR_PER_PA_R8
570 end do
571 qs = col_getElem(columnTrlOnTrlLev, nlv_T, headerIndex, 'HU')
572
573 bodyStart = obs_headElem_i(obsSpaceData, OBS_RLN, headerIndex)
574 bodyEnd = obs_headElem_i(obsSpaceData, OBS_NLV, headerIndex) + bodyStart - 1
575 bad = .false.
576 if (lcris) bad=( obs_headElem_i(obsSpaceData, OBS_GQF, headerIndex)/=0 .or. &
577 obs_headElem_i(obsSpaceData, OBS_GQL, headerIndex) /=0)
578 if (liasi) bad=( obs_headElem_i(obsSpaceData, OBS_GQF, headerIndex)/=0 .or. &
579 obs_headElem_i(obsSpaceData, OBS_GQL, headerIndex) >1)
580
581 nchannels = 0 ! number of channels available at that observation point
582 do bodyIndex= bodyStart, bodyEnd
583 if ( obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated ) then
584 channelNumber = nint(obs_bodyElem_r(obsSpaceData,OBS_PPP,bodyIndex))
585 channelNumber = max( 0,min( channelNumber,tvs_maxChannelNumber + 1 ) )
586 call tvs_getLocalChannelIndexFromChannelNumber(id,channelIndex,channelNumber)
587 if (channelIndex == -1) cycle
588 nchannels = nchannels + 1
589 channelIndexes(nchannels) = channelIndex
590 btObsErr(channelIndex) = obs_bodyElem_r(obsSpaceData,OBS_OER,bodyIndex)
591 btObs(channelIndex) = obs_bodyElem_r(obsSpaceData,OBS_VAR,bodyIndex)
592
593 ! Flag check on observed BTs ***
594 if (.not.liasi .and. btest(obs_bodyElem_i(obsSpaceData,OBS_FLG,bodyIndex),2)) rejflag(channelIndex,9) = 1
595 if (bad) rejflag(channelIndex,9) = 1
596
597 ! Gross check on observed BTs ***
598 if (btObs(channelIndex)<150.d0) rejflag(channelIndex,9) = 1
599 if (btObs(channelIndex)>350.d0) rejflag(channelIndex,9) = 1
600 end if
601 end do
602
603 if (nchannels==0) cycle HEADER_2
604
605 do jc = 1, nchannels
606 channelIndex = channelIndexes(jc)
607 if ( channelIndex ==-1) cycle
608 btCalc(channelIndex) = tvs_radiance(tvs_nobtov) % bt(channelIndex)
609 rcal_clr(channelIndex) = tvs_radiance(tvs_nobtov) % clear(channelIndex)
610 sfctau(channelIndex) = tvs_transmission(tvs_nobtov) % tau_total(channelIndex)
611 do levelIndex = 1, nlv_T
612 transm(channelIndex,levelIndex) = tvs_transmission(tvs_nobtov) % tau_levels(levelIndex, channelIndex)
613 end do
614 do levelIndex = 1, nlv_T - 1
615 cloudyRadiance(channelIndex,levelIndex) = tvs_radiance(tvs_nobtov) % overcast(levelIndex, channelIndex)
616 end do
617 emi_sfc(channelIndex) = tvs_emissivity(channelIndex,tvs_nobtov)
618 ! Gross check on computed BTs ***
619 if (btCalc(channelIndex) < 150.d0) rejflag(channelIndex,9) = 1
620 if (btCalc(channelIndex) > 350.d0) rejflag(channelIndex,9) = 1
621 end do
622
623 ksurf = profiles(tvs_nobtov) % skin % surftype
624
625 !Test pour detecter l angle zenithal manquant (-1) ou anormal
626 ! (angle negatif ou superieur a 75 degres )
627 satelliteZenithAngle= obs_headElem_r(obsSpaceData, OBS_SZA, headerIndex)
628 if ( satelliteZenithAngle < 0 .or. satelliteZenithAngle > 75. ) then
629 rejflag(:,9) = 1
630 satelliteZenithAnglePresent = .false.
631 else
632 satelliteZenithAnglePresent = .true.
633 end if
634 clfr = 0.
635 if (lairs .or. lcris) clfr = obs_headElem_r(obsSpaceData, OBS_CLF, headerIndex)
636
637 sunZenithAngle = profiles(tvs_nobtov) % sunzenangle
638 sunZenithAnglePresent = ( abs(sunZenithAngle - MPC_missingValue_R8) > 0.01 )
639
640 if (liasi) then
641 satelliteAzimuthAngle = profiles(tvs_nobtov) % azangle
642 satelliteAzimuthAnglePresent = ( abs(satelliteAzimuthAngle - MPC_missingValue_R8) > 0.01 )
643 end if
644 albedo = tvs_surfaceParameters(tvs_nobtov) % albedo
645 ice = tvs_surfaceParameters(tvs_nobtov) % ice
646 ltype = tvs_surfaceParameters(tvs_nobtov) % ltype
647 if (ltype == 20) ksurf = 2
648 pcnt_wat = tvs_surfaceParameters(tvs_nobtov) % pcnt_wat
649 pcnt_reg = tvs_surfaceParameters(tvs_nobtov) % pcnt_reg
650
651 ! Find TOA radiances converted from observed BT's
652
653 radObs(:) = -1.d0
654
655 channels: do jc = 1, nchannels
656 channelIndex = channelIndexes(jc)
657 if (channelIndex == -1) cycle channels
658 if ( rejflag(channelIndex,9) == 1 ) cycle channels
659 t_effective = tvs_coefs(id) % coef % ff_bco(channelIndex) &
660 + tvs_coefs(id) % coef % ff_bcs(channelIndex) * btObs(channelIndex)
661 radObs(channelIndex) = tvs_coefs(id) % coef % planck1(channelIndex) / &
662 ( exp( tvs_coefs(id) % coef % planck2(channelIndex) / t_effective ) - 1.d0 )
663 end do channels
664
665 ! Set height fields to 'height above ground' fields
666 do levelIndex = 1, nlv_T - 1
667 height(levelIndex,1) = height(levelIndex,1) - height(nlv_T-1,1)
668 end do
669
670 ! ///// ---------------------------------------------------- /////
671 ! ///// Determination of the clear/cloudy profiles (cldflag) /////
672 ! ///// ---------------------------------------------------- /////
673 cldflag = 0
674
675 ! Reference for window channel
676 call tvs_getLocalChannelIndexFromChannelNumber(id, iwindo, iwindow(qcid) )
677 call tvs_getLocalChannelIndexFromChannelNumber(id, iwindo_alt, iwindow_alt(qcid) )
678 ichref = -1
679 if (iwindo /= -1) then
680 if ( rejflag(iwindo,9) == 0) then
681 ichref = iwindo
682 end if
683 end if
684 if (ichref == -1 .and. iwindo_alt /= -1) then
685 if ( rejflag(iwindo_alt,9) == 0) then
686 ichref = iwindo_alt
687 end if
688 end if
689
690 if (ichref == -1) then
691 cldflag = -1
692 rejflag(:,9) = 1
693 write(*,*) 'WARNING'
694 write(*,*) 'WINDOW AND ALTERNATE WINDOW CHANNEL OBSERVATIONS'
695 write(*,*) 'HAVE BEEN REJECTED. '
696 write(*,*) 'ALL '//instrumentName//' OBSERVATIONS FROM THIS PROFILE REJECTED'
697 end if
698
699 ! -- Cloud top based on matching observed brightness temperature
700 ! -- at a reference surface channel with background temperature profile (ptop_eq)
701 ! -- on guess vertical levels.
702
703 lev_start = 0
704
705 !iopt2=1 : calcul de la hauteur en hPa ptop_mb et du ntop_mb correspondant
706 call cloud_height ( ptop_mb, ntop_mb, btObs, cldflag, tt, &
707 height(:,1), p0, pressure(:,1), ichref, lev_start, iopt2 )
708
709 !iopt1=2 : calcul de la hauteur em metres ptop_eq et du ntop_eq correspondant
710 call cloud_height ( ptop_eq, ntop_eq, btObs, cldflag, tt, &
711 height(:,1), p0, pressure(:,1), ichref, lev_start, iopt1 )
712
713 if (liasi) then
714 ! appel de RTTOV pour calculer les radiances des 3 canaux IR (3b, 4 et 5) de AVHRR 3
715
716 call get_avhrr_emiss(emi_sfc(channelIndexes(1:nchannels)),tvs_coefs(id) % coef % ff_cwn(channelIndexes(1:nchannels)), &
717 nchannels,avhrr_surfem1)
718
719 call tovs_rttov_avhrr_for_IASI(headerIndex,avhrr_surfem1,tvs_satellites(id))
720
721 !The value computed will be used only if sunZenithAnglePresent is true
722 call convert_avhrr(sunZenithAngle, avhrr_bgck(headerIndex) )
723 call stat_avhrr(avhrr_bgck(headerIndex))
724
725 lev_start_avhrr(:) = 0
726 cldflag_avhrr(:) = 0
727 do classIndex = 1, nClassAVHRR
728 btObs_avhrr(:,classIndex) = avhrr_bgck(headerIndex) % tbmoy(classIndex,:)
729 radObs_avhrr(1:NIR,classIndex) = avhrr_bgck(headerIndex) % radmoy(classIndex,NVIS + 1:NIR + NVIS)
730 rcal_clr_avhrr(:) = avhrr_bgck(headerIndex) % radclearcalc(:)
731 emi_sfc_avhrr(:) = avhrr_bgck(headerIndex) % emiss(:)
732 sfctau_avhrr(:) = avhrr_bgck(headerIndex) % transmsurf(:)
733
734 do levelIndex = 1, nlv_T - 1
735 cloudyRadiance_avhrr(:,levelIndex) = avhrr_bgck(headerIndex) % radovcalc(levelIndex,:)
736 end do
737
738 if (btObs_avhrr(2,classIndex) > 100.d0 ) then
739 ichref_avhrr(classIndex) = 2
740 else if (btObs_avhrr(3,classIndex) > 100.d0 ) then
741 ichref_avhrr(classIndex) = 3
742 else
743 ichref_avhrr(classIndex) = -1
744 cldflag_avhrr(classIndex) = -1
745 end if
746
747 call cloud_height (ptop_eq_avhrr(classIndex),ntop_eq_avhrr(classIndex), btObs_avhrr(:,classIndex),cldflag_avhrr(classIndex),tt, &
748 height(:,1),p0,pressure,ichref_avhrr(classIndex),lev_start_avhrr(classIndex),iopt1)
749 end do
750
751 end if
752
753 ! -- Clear/cloudy profile detection using the garand & nadon algorithm
754
755 call garand1998nadon (cldflag, btObs,tg,tt, &
756 height(:,1),ptop_eq,ntop_eq,ichref)
757
758 if (liasi) then
759 do classIndex=1,nClassAVHRR
760 call garand1998nadon (cldflag_avhrr(classIndex), btObs_avhrr(:,classIndex),tg,tt, &
761 height(:,1),ptop_eq_avhrr(classIndex),ntop_eq_avhrr(classIndex),ichref_avhrr(classIndex))
762 end do
763 end if
764
765 ! Further tests to remove potential cloudy profiles
766 ! Test # A
767 ! In daytime, set cloudy if cloud fraction over 5%
768 cfsub = -1.d0
769 if (lairs) then
770 if ( cldflag == 0 .and. clfr > 5.d0 .and. sunZenithAngle < 90.d0 .and. sunZenithAnglePresent) then
771 cldflag = 1
772 cfsub = 0.01d0 * clfr !conversion % -> 0-1
773 end if
774 end if
775 if (lcris) then
776 if ( cldflag == 0 .and. clfr >= 0.d0 .and. clfr > crisCloudFractionThreshold &
777 .and. crisCloudFractionThreshold >= 0.d0 ) then
778 cldflag = 1
779 cfsub = 0.01d0 * clfr !conversion % -> 0-1
780 end if
781 end if
782 ! Test # B
783 ! Set cloudy if temperature difference between guess (tg)
784 ! and estimated true (tskinRetrieved) skin temperatures is over threshold
785
786 call estim_ts(tskinRetrieved, tg, emi_sfc, rcal_clr, radObs, &
787 sfctau, cldflag, ichref, tvs_coefs(id) )
788
789 if ( cldflag == 0 .and. ksurf == 1 &
790 .and. abs(tskinRetrieved-tg) > dtw ) cldflag = 1
791
792 if ( cldflag == 0 .and. ksurf /= 1 &
793 .and. abs(tskinRetrieved-tg) > dtl ) cldflag = 1
794
795 if (liasi) then
796
797 do classIndex = 1, nClassAVHRR
798 call estim_ts(tskinRetrieved_avhrr(classIndex), tg,emi_sfc_avhrr,rcal_clr_avhrr,radObs_avhrr(:,classIndex), &
799 sfctau_avhrr,cldflag_avhrr(classIndex),ichref_avhrr(classIndex), coefs_avhrr)
800 end do
801
802 do classIndex = 1, nClassAVHRR
803 if ( cldflag_avhrr(classIndex) == 0 .and. ksurf == 1 &
804 .and. abs(tskinRetrieved_avhrr(classIndex)-tg) > dtw ) cldflag_avhrr(classIndex) = 1
805
806 if ( cldflag_avhrr(classIndex) == 0 .and. ksurf /= 1 &
807 .and. abs(tskinRetrieved_avhrr(classIndex)-tg) > dtl ) cldflag_avhrr(classIndex) = 1
808
809 end do
810
811 !criteres AVHRR utilisant les canaux visibles (de jour seulement)
812 if ( sunZenithAngle < sunzenmax .and. sunZenithAnglePresent .and. satelliteAzimuthAnglePresent .and. &
813 sunAzimuthAnglePresent .and. satelliteZenithAnglePresent) then
814 anisot = 1.d0
815
816 if (albedo < albedoThresholdQC) then
817 deltaphi = abs(satelliteAzimuthAngle - sunAzimuthAngle )
818 if (deltaphi > 180.d0) deltaphi = 360.d0 - deltaphi
819 call visocn(sunZenithAngle,satelliteZenithAngle,deltaphi,anisot,zlamb,zcloud,IER)
820 albedoThreshold = 10.d0 * max(1.d0,anisot)
821 else
822 albedoThreshold = 100.d0 * albedo + 10.d0
823 end if
824
825 if (anisot < 1.5d0) then !to avoid sun glint
826 scos = cos ( sunZenithAngle * MPC_DEGREES_PER_RADIAN_R8 )
827 call cor_albedo (del, scos )
828 albedoThreshold = albedoThreshold * del
829 do classIndex = 1, nClassAVHRR
830 if (avhrr_bgck(headerIndex)%albedmoy(classIndex,1) > albedoThreshold(1) ) then
831 cldflag_avhrr(classIndex) = 1
832 end if
833 !static AVHRR thresholds v3
834 do channelIndex = 1, NVIS
835 if (avhrr_bgck(headerIndex)%albedmoy(classIndex,channelIndex) > seuilalb_static(channelIndex,ksurf) ) then
836 cldflag_avhrr(classIndex) = 1
837 end if
838 end do
839 end do
840
841 end if
842 end if
843
844 ! Calcul de la pseudo fraction nuageuse AVHRR
845
846 cfrac_avhrr = 0.d0
847 do classIndex = 1, nClassAVHRR
848 if (cldflag_avhrr(classIndex) == 1) cfrac_avhrr = cfrac_avhrr + avhrr_bgck(headerIndex) % cfrac(classIndex)
849 end do
850
851 cfsub = -1.0d0
852 if ( cldflag == 0 .and. cfrac_avhrr > 5.d0 ) then
853 cldflag = 1
854 cfsub = 0.01d0 * min(cfrac_avhrr, 100.d0) !conversion % -> 0-1 avec seuil car parfois cfrac_avhrr=101
855 end if
856
857 !AVHRR Homogeneity criteria
858 if (cldflag == 0 .and. sunZenithAnglePresent) then
859 ijour = 1
860 if (sunZenithAngle < 90.d0) ijour=2
861 ! 1 NUIT
862 ! 2 JOUR
863 if (ijour == 2) then
864 do channelIndex=1,NVIS
865 if (avhrr_bgck(headerIndex)%albstd_pixeliasi(channelIndex) > seuilalb_homog(channelIndex,ksurf) ) cldflag = 1
866 end do
867 end if
868 do channelIndex=NVIS+1,NVIS+NIR
869 if (avhrr_bgck(headerIndex)%tbstd_pixelIASI(channelIndex) > seuilbt_homog(channelIndex,ksurf,ijour)) cldflag = 1
870 end do
871 end if
872 end if
873
874 gncldflag = cldflag
875
876 ! ///// ------------------------------------------------------- /////
877 ! ///// DETERMINATION OF THE ASSIMILABLE OBSERVATIONS (rejflag) /////
878 ! ///// ------------------------------------------------------- /////
879
880
881 ! -- FIRST TestS TO REJECT OBSERVATIONS
882
883
884 ! *** Test # 1 ***
885 ! *** Do not assimilate where cloudy ***
886
887 if ( cldflag == 1 ) then
888 rejflag(:,11) = 1
889 rejflag(:,23) = 1
890 end if
891
892 ! *** Test # 2 ***
893 ! *** Gross check on valid BTs ***
894
895 ! already done
896
897
898 ! -- Cloud top based on matching
899 ! -- observed brightness temperature with background temperature profiles (ptop_bt)
900 ! -- or computed observed radiances with background radiance profiles (ptop_rd)
901 ! -- on rttov vertical levels
902
903 lev_start = 0
904
905 do channelIndex = 1, nch_he
906 call tvs_getLocalChannelIndexFromChannelNumber(id,ilist_HE(channelIndex),ilist1(qcid,channelIndex))
907 end do
908 !here the case for which one of the channelindex is -1 is treated in cloud_top
909 call cloud_top ( ptop_bt,ptop_rd,ntop_bt,ntop_rd, &
910 btObs,tt,height(:,1),rcal_clr,p0,radObs,cloudyRadiance,pressure(:,1), &
911 cldflag, lev_start, iopt2, ihgt, ilist_he,rejflag_opt=rejflag,ichref_opt=ichref)
912
913 if (liasi) then
914 lev_start_avhrr(:) = 0
915 do classIndex = 1, nClassAVHRR
916 call cloud_top( ptop_bt_avhrr(:,classIndex),ptop_rd_avhrr(:,classIndex),ntop_bt_avhrr(:,classIndex),ntop_rd_avhrr(:,classIndex), &
917 btObs_avhrr(:,classIndex),tt,height(:,1),rcal_clr_avhrr,p0,radObs_avhrr(:,classIndex),cloudyRadiance_avhrr,pressure(:,1), &
918 cldflag_avhrr(classIndex),lev_start_avhrr(classIndex),iopt2,ihgt,ilist_avhrr)
919 end do
920 end if
921
922 ! -- reference channel for co2-slicing
923
924 do channelIndex = 1, nco2
925 call tvs_getLocalChannelIndexFromChannelNumber(id, ilist_co2(channelIndex), ilist2(qcid,channelIndex) )
926 call tvs_getLocalChannelIndexFromChannelNumber(id, ilist_co2_pair(channelIndex), ilist2_pair(qcid,channelIndex) )
927 end do
928
929 countInvalidChannels = 0
930 do channelIndex = 1, nco2
931 if ( ilist_co2(channelIndex) == -1 .or. ilist_co2_pair(channelIndex) == -1 ) then
932 countInvalidChannels = countInvalidChannels + 1
933 else if ( rejflag(ilist_co2(channelIndex),9) == 1 .or. &
934 rejflag(ilist_co2_pair(channelIndex),9) == 1 ) then
935 countInvalidChannels = countInvalidChannels + 1
936 end if
937 end do
938
939 if (countInvalidChannels == nco2) then
940 cldflag = -1
941 rejflag(:,9) = 1
942 write(*,*) 'WARNING'
943 write(*,*) 'CO2 REFERENCE AND ALTERNATE CHANNEL OBSERVATIONS'
944 write(*,*) 'HAVE BEEN REJECTED. '
945 write(*,*) 'ALL '//instrumentName//' OBSERVATIONS FROM THIS PROFILE REJECTED'
946 end if
947
948 ! Equivalent height of selected window channel
949 heff = MPC_missingValue_R8
950 call tvs_getLocalChannelIndexFromChannelNumber(id,channelIndex,ilist1(qcid,2))
951 if (channelIndex /= -1) heff = ptop_rd( channelIndex )
952
953 if (ichref == iwindo_alt) then
954 call tvs_getLocalChannelIndexFromChannelNumber(id,channelIndex,ilist1(qcid,3))
955 if (channelIndex /= -1) heff = ptop_rd( channelIndex )
956 end if
957 ! Cloud top based on co2 slicing
958
959 co2min = minloc( abs( pressure(:,1) - pco2min ) )
960 co2max = minloc( abs( pressure(:,1) - pco2max ) )
961
962 lev_start = max( min(lev_start,co2max(1)), co2min(1) )
963
964 call co2_slicing ( ptop_co2, ntop_co2, fcloud_co2, &
965 rcal_clr, cloudyRadiance, radObs, p0, pressure(:,1), cldflag, rejflag, &
966 lev_start, ichref, ilist_co2, ilist_co2_pair)
967
968 ! -- Find consensus cloud top and fraction
969
970 call seltop ( etop,vtop,ecf,vcf,ngood, heff,ptop_co2,fcloud_co2, &
971 cfsub,ptop_mb,p0,cldflag,gncldflag )
972
973 if (liasi) then
974 ! Correction pour les nuages trop bas:
975 ! en principe Pco2 < Heff.
976 ! on cherche les cas pathologiques avec Pco2>Min(Heff(AVHRR))
977 minpavhrr(2:3) = 12200
978 iloc(2:3) = -1 ! pour eviter les catastrophes...
979 do classIndex=1,nClassAVHRR
980 if (avhrr_bgck(headerIndex)%cfrac(classIndex) > 0.d0) then
981 if (ptop_rd_avhrr(2,classIndex) < minpavhrr(2)) then
982 iloc(2) = classIndex
983 minpavhrr(2) = ptop_rd_avhrr(2,classIndex)
984 end if
985 if (ptop_rd_avhrr(3,classIndex) < minpavhrr(3)) then
986 iloc(3) = classIndex
987 minpavhrr(3) = ptop_rd_avhrr(3,classIndex)
988 end if
989 end if
990 end do
991 if ( iloc(2) /= -1 .and. iloc(3) /= -1) then ! pour eviter les catastrophes...
992 ! on se limite aux cas "surs" ou les deux hauteurs effectives sont > a Pco2
993 ! et ou un accord raisonnable existe entre les deux hauteurs effectives
994 if ( iloc(2) == iloc(3) .and. &
995 minpavhrr(2) < etop .and. &
996 minpavhrr(3) < etop .and. &
997 abs(minpavhrr(2)- minpavhrr(3)) < 25.d0 .and. &
998 cldflag_avhrr(iloc(2)) /= -1 .and. cldflag_avhrr(iloc(3)) /= -1) then
999
1000 if (ecf == 0.d0 .and. cldflag == 1) then
1001 ! cas predetermine nuageux mais ramene a clair
1002 ecf = 0.01d0 * min(100.d0,cfrac_avhrr)
1003 ! cette ligne peut generer des fractions nuageuses inferieures a 20 %.
1004 etop = 0.5d0 * (minpavhrr(2) + minpavhrr(3))
1005 end if
1006
1007 if (ecf > 0.d0 .and. cldflag == 1) then
1008 !cas predetermine nuageux pas ramene clair (==normal)
1009 etop = 0.5d0 * ( minpavhrr(2) + minpavhrr(3))
1010 end if
1011
1012 if (cldflag == 0) then
1013 !cas predetermine clair ... que faire
1014 cldflag = 1
1015 etop = 0.5d0 * (minpavhrr(2) + minpavhrr(3))
1016 ecf = 0.01d0 * min(100.d0,cfrac_avhrr)
1017 end if
1018 end if
1019 end if
1020 end if
1021
1022 ! -- Find minimum level of sensitivity for channel assimilation not sensible to clouds
1023 call min_pres_new (maxwf, minp, pmin, dtaudp1, p0, transm(:,2:nlv_T), pressure(:,1), cldflag, modelTopIndex)
1024 ! -- ASSIMILATION OF OBSERVATIONS WHEN CLOUDY PROFILES
1025
1026 ! *** Test # 3 ***
1027 ! *** Assimilation above clouds (refinement of test 1) ***
1028 ! *** Set security margin to 2x the std on height from CO2-slicing ***
1029
1030 tampon = max(50.d0, 2.d0*vtop)
1031
1032 do channelIndex = 1, nchn
1033 if ( rejflag(channelIndex,11) == 1 .and. rejflag(channelIndex,23) == 1 .and. etop - tampon > pmin(channelIndex) ) then
1034 rejflag(channelIndex,11) = 0
1035 rejflag(channelIndex,23) = 0
1036 end if
1037 end do
1038
1039 ! Look at the fate of the observations
1040 fate(:) = sum(rejflag(:,:), DIM=2)
1041
1042 ! Further reasons to reject observations
1043 do channelIndex = 1, nchn
1044
1045 if ( fate(channelIndex) == 0 ) then
1046
1047 ! *** Test # 4 ***
1048 ! *** Background check, do not assimilate if O-P > 3sigma ***
1049
1050 if ( abs(btObs(channelIndex) - btCalc(channelIndex)) > 3.d0 * btObsErr(channelIndex) ) then
1051 rejflag(channelIndex,9) = 1
1052 rejflag(channelIndex,16) = 1
1053 end if
1054
1055 ! *** Test # 5 ***
1056 ! *** Do not assimilate shortwave channels during the day ***
1057
1058 if ( tvs_coefs(id) % coef % ff_cwn(channelIndex) >= 2000.d0 .and. sunZenithAngle < night_ang .and. sunZenithAnglePresent) then
1059 rejflag(channelIndex,11) = 1
1060 rejflag(channelIndex,7) = 1
1061 end if
1062
1063 ! *** Test # 6 ***
1064 ! *** Do not assimilate surface channels over land ***
1065
1066 if ( minp(channelIndex) == nlv_T .or. p0-pmin(channelIndex) < 100.d0 ) then
1067 if ( ksurf == 0 ) then
1068 rejflag(channelIndex,11) = 1 !!! comment this line if assimilation under conditions
1069 rejflag(channelIndex,19) = 1 !!! comment this line if assimilation under conditions
1070 if ( pcnt_wat > 0.01d0 .or. pcnt_reg > 0.1d0 .or. emi_sfc(channelIndex) < 0.97d0 ) then
1071 rejflag(channelIndex,11) = 1
1072 rejflag(channelIndex,19) = 1
1073 end if
1074
1075 ! *** Test # 7 ***
1076 ! *** Do not assimilate surface channels over water under conditions ***
1077
1078 else if ( ksurf == 1 ) then
1079 if ( pcnt_wat < 0.99d0 .or. pcnt_reg < 0.97d0 .or. &
1080 ice > 0.001d0 .or. albedo >= albedoThresholdQC .or. emi_sfc(channelIndex) < 0.9d0 ) then
1081 rejflag(channelIndex,11) = 1
1082 rejflag(channelIndex,19) = 1
1083 end if
1084
1085 ! *** Test # 8 ***
1086 ! *** Do not assimilate surface channels over sea ice ***
1087
1088 else if ( ksurf == 2 ) then
1089 rejflag(channelIndex,11) = 1
1090 rejflag(channelIndex,19) = 1
1091 end if
1092 end if
1093
1094 end if
1095
1096 ! *** Test # 9 ***
1097 ! *** Do not assimilate if jacobian has a significant contribution over model top ***
1098
1099 ! Condition valid if model top at 10mb or lower only
1100 if ( nint(ptop_T) >= 1000 ) then
1101 if ( rejflag(channelIndex,9) /= 1 .and. dtaudp1(channelIndex) > 0.50d0 ) then
1102 rejflag(channelIndex,11) = 1
1103 rejflag(channelIndex,21) = 1
1104 end if
1105 end if
1106
1107 ! Condition valid if model top at 10mb or lower only
1108 if ( nint(ptop_T) >= 1000 ) then
1109 if ( rejflag(channelIndex,9) /= 1 .and. transm(channelIndex,1) < 0.99d0 ) then
1110 rejflag(channelIndex,11) = 1
1111 rejflag(channelIndex,21) = 1
1112 end if
1113 end if
1114
1115 ! Condition valid if model top is higher than 10 mb
1116 ! with computation made on model levels instead of RTTOV levels
1117 ! this test is a litle bit more strict than before
1118 ! decrease of the order of 1-2% in the number of high peaking radiance IR assimilated
1119 ! not dramatic so could be kept as is
1120 if ( nint(ptop_T) < 1000 ) then
1121 if ( rejflag(channelIndex,9) /= 1 .and. transm(channelIndex,1) < 0.95d0 ) then
1122 rejflag(channelIndex,11) = 1
1123 rejflag(channelIndex,21) = 1
1124 end if
1125 end if
1126
1127 end do
1128
1129 nchannels =0
1130 do bodyIndex= bodyStart, bodyEnd
1131 if ( obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated ) then
1132 nchannels = nchannels + 1
1133 if (btest(obs_bodyElem_i(obsSpaceData,OBS_FLG,bodyIndex),8)) rejflag(channelIndexes(nchannels),8) = 1
1134 end if
1135 end do
1136
1137 ! For each profile, are all non-blacklisted channels assimilated
1138
1139 assim_all = .true.
1140 fate(:) = sum(rejflag(:,:),DIM=2)
1141
1142 chn: do channelIndex = 1, nchn
1143 if ( rejflag(channelIndex,8) == 0 ) then
1144 if ( fate(channelIndex) /= 0 ) then
1145 assim_all = .false.
1146 exit chn
1147 end if
1148 end if
1149 end do chn
1150
1151 if (.not.assim_all) then
1152 call obs_headSet_i(obsSpaceData, OBS_ST1, headerIndex,ibset(obs_headElem_i(obsSpaceData,OBS_ST1,headerIndex),6) )
1153 end if
1154 ! -- Addition of background check parameters to burp file
1155
1156 call obs_headSet_r(obsSpaceData, OBS_ETOP, headerIndex, etop )
1157 call obs_headSet_r(obsSpaceData, OBS_VTOP, headerIndex, vtop )
1158 call obs_headSet_r(obsSpaceData, OBS_ECF, headerIndex, 100.d0 * ecf )
1159 call obs_headSet_r(obsSpaceData, OBS_VCF, headerIndex, 100.d0 * vcf )
1160 call obs_headSet_r(obsSpaceData, OBS_HE, headerIndex, heff )
1161 call obs_headSet_r(obsSpaceData, OBS_ZTSR, headerIndex, tskinRetrieved )
1162 call obs_headSet_i(obsSpaceData, OBS_NCO2, headerIndex, ngood)
1163 call obs_headSet_r(obsSpaceData, OBS_ZTM, headerIndex, tt(nlv_T-1) )
1164 call obs_headSet_r(obsSpaceData, OBS_ZTGM, headerIndex, tg )
1165 call obs_headSet_r(obsSpaceData, OBS_ZLQM, headerIndex, qs )
1166 call obs_headSet_r(obsSpaceData, OBS_ZPS, headerIndex, 100.d0 * p0 )
1167 call obs_headSet_i(obsSpaceData, OBS_STYP, headerIndex, ksurf )
1168
1169 do bodyIndex = bodyStart, bodyEnd
1170 channelNumber = nint(obs_bodyElem_r(obsSpaceData,OBS_PPP,bodyIndex))
1171 channelNumber = max(0, min(channelNumber, tvs_maxChannelNumber + 1))
1172 call tvs_getLocalChannelIndexFromChannelNumber(id,channelIndex,channelNumber)
1173 if (channelIndex == -1) cycle
1174 call obs_bodySet_r(obsSpaceData,OBS_SEM,bodyIndex,emi_sfc(channelIndex))
1175 do bitIndex = 0, bitflag
1176 if ( rejflag(channelIndex,bitIndex) == 1 ) &
1177 call obs_bodySet_i(obsSpaceData,OBS_FLG,bodyIndex,IBSET(obs_bodyElem_i(obsSpaceData,OBS_FLG,bodyIndex),bitIndex))
1178 end do
1179 end do
1180
1181 end if
1182
1183 end do HEADER_2
1184
1185 deallocate ( channelIndexes, stat= allocStatus(1))
1186 deallocate ( height, stat= allocStatus(2))
1187 deallocate ( tt, stat= allocStatus(3))
1188 deallocate ( pressure, stat= allocStatus(4))
1189 deallocate ( maxwf, stat= allocStatus(5))
1190 if (liasi) deallocate ( cloudyRadiance_avhrr , stat= allocStatus(6))
1191 deallocate ( fate, stat= allocStatus(7))
1192 deallocate ( dtaudp1, stat= allocStatus(8))
1193 deallocate ( pmin, stat= allocStatus(9))
1194 deallocate ( minp, stat= allocStatus(10))
1195 deallocate ( ptop_rd, stat= allocStatus(11))
1196 deallocate ( ptop_bt, stat= allocStatus(12))
1197 deallocate ( ntop_rd, stat= allocStatus(13))
1198 deallocate ( ntop_bt, stat= allocStatus(14))
1199 deallocate ( rejflag, stat= allocStatus(15))
1200 deallocate ( radObs, stat= allocStatus(16))
1201 deallocate ( emi_sfc, stat= allocStatus(17))
1202 deallocate ( transm, stat= allocStatus(18))
1203 deallocate ( cloudyRadiance, stat= allocStatus(19))
1204 deallocate ( sfctau, stat= allocStatus(20))
1205 deallocate ( rcal_clr, stat= allocStatus(21))
1206 deallocate ( btCalc, stat= allocStatus(22))
1207 deallocate ( btObs, stat= allocStatus(23))
1208 deallocate ( btObsErr, stat= allocStatus(24))
1209 call utl_checkAllocationStatus(allocStatus, " irbg_doQualityControl", .false.)
1210 nullify(profiles)
1211
1212 end subroutine irbg_doQualityControl
1213
1214
1215 !--------------------------------------------------------------------------
1216 ! convert_avhrr
1217 !--------------------------------------------------------------------------
1218 subroutine convert_avhrr(sunzen, avhrr)
1219 !
1220 !:Purpose: conversion des radiance IR en temperatures de brillance
1221 ! et des radiances visibles en "albedo"
1222
1223 implicit none
1224
1225 ! Arguments:
1226 real(8), intent(in) :: sunzen ! Solar zenith angle
1227 type (avhrr_bgck_iasi), intent(inout) :: avhrr ! Structure containing AVHRR observations
1228
1229 ! Locals:
1230 integer :: classIndex
1231 real(8) :: bt(NIR), dbtsdrad(NIR)
1232 real(8) :: freq(NIR), offset(NIR), slope(NIR)
1233
1234 freq = coefs_avhrr%coef%ff_cwn (:)
1235 offset = coefs_avhrr%coef%ff_bco(:)
1236 slope = coefs_avhrr%coef%ff_bcs(:)
1237
1238 do classIndex=1, nClassAVHRR
1239 call calcbt(avhrr % radmoy(classIndex,4:6), bt, dbtsdrad, freq, offset, slope)
1240 avhrr % tbmoy(classIndex,4:6) = bt(1:3)
1241 avhrr % tbstd(classIndex,4:6) = avhrr % radstd(classIndex,4:6) * dbtsdrad(1:3)
1242 call calcreflect(avhrr % radmoy(classIndex,1:3), sunzen, avhrr % albedmoy(classIndex,1:3) )
1243 call calcreflect(avhrr % radstd(classIndex,1:3), sunzen, avhrr % albedstd(classIndex,1:3) )
1244 end do
1245
1246 end subroutine convert_avhrr
1247
1248 !--------------------------------------------------------------------------
1249 ! calcreflect
1250 !--------------------------------------------------------------------------
1251 subroutine calcreflect(rad, sunzen, reflect)
1252 !
1253 !:Purpose: Computes Top of Atmosphere Albedo as defined by equation (4)
1254 ! of Rao et al. Int. J. of Remote Sensing, 2003, vol 24, no 9, 1913-1924
1255 !
1256 implicit none
1257
1258 ! Arguments:
1259 real(8), intent(in) :: rad(nvis) ! radiances array
1260 real(8), intent(in) :: sunzen ! Sun zenith angle
1261 real(8), intent(out):: reflect(nvis) ! TOA albedo en %
1262
1263 ! Locals:
1264 real(8),parameter :: solar_filtered_irradiance(nvis) = (/139.873215d0,232.919556d0,14.016470d0/)
1265 ! equivalent widths, integrated solar irradiance, effective central wavelength
1266 !0.084877,139.873215,0.632815
1267 !0.229421,232.919556,0.841679
1268 !0.056998,14.016470,1.606119
1269 real(8) :: radb ! radiance en W/m2/str
1270 integer :: i
1271
1272 do i = 1, nvis
1273 if (rad(i) >= 0.0d0 ) then
1274 radb = rad(i) / 1000.0d0
1275 reflect(i) = (MPC_PI_R8 * radb) / solar_filtered_irradiance(i)
1276 if (sunzen < 90.0d0 ) reflect(i) = reflect(i) / cos(sunzen * MPC_RADIANS_PER_DEGREE_R8)
1277 else
1278 reflect(i) = -1
1279 end if
1280 end do
1281
1282 end subroutine calcreflect
1283
1284 !--------------------------------------------------------------------------
1285 ! calcbt
1286 !--------------------------------------------------------------------------
1287 subroutine calcbt(rad, tb, dtbsdrad, freq, offset, slope)
1288 !
1289 !:Purpose: Computes brightness temperature (bt) and the first derivative of
1290 ! bt with respect to radiance, from radiance, frequencies
1291 !
1292 !
1293 implicit none
1294
1295 ! Arguments:
1296 real(8), intent(in) :: rad(:) ! Radiance
1297 real(8), intent(in) :: freq(size(rad)) ! Channel wavenumber (cm-1)
1298 real(8), intent(in) :: offset(size(rad)) !
1299 real(8), intent(in) :: slope(size(rad)) !
1300 real(8), intent(out) :: tb(size(rad)) ! Brightness Temperature
1301 real(8), intent(out) :: dtbsdrad(size(rad)) ! Derivative of tb wrt radiance
1302
1303 ! Locals:
1304 integer :: channelIndex, nchan
1305 real(8) :: radtotal, tstore, planck1, planck2
1306 real(8), parameter :: c1= 1.19106590d-05 ! First Planck constant
1307 real(8), parameter :: c2= 1.438833d0 ! Second Planck constant
1308
1309 nchan = size(rad)
1310
1311 do channelIndex = 1, nchan
1312 if (rad(channelIndex) > 1.d-20) then
1313 planck2 = c2 * freq(channelIndex)
1314 planck1 = c1 * ( freq(channelIndex) ** 3 )
1315 tstore = planck2 / log( 1.0d0 + planck1 / rad(channelIndex) )
1316 tb(channelIndex) = ( tstore - offset(channelIndex) ) / slope(channelIndex)
1317
1318 radtotal = rad(channelIndex)
1319
1320 dtbsdrad(channelIndex) = planck1 * tstore ** 2 / ( planck2 * radtotal * ( radtotal + planck1 ) )
1321
1322 dtbsdrad(channelIndex) = dtbsdrad(channelIndex) / slope(channelIndex)
1323
1324 else
1325 tb(channelIndex) = 0.d0
1326 dtbsdrad(channelIndex) = 0.d0
1327 end if
1328
1329 end do
1330
1331 end subroutine calcbt
1332
1333 !--------------------------------------------------------------------------
1334 ! stat_avhrr
1335 !--------------------------------------------------------------------------
1336 subroutine stat_avhrr( avhrr )
1337 !
1338 !:Purpose: calcul de statistiques
1339 ! sur l'information sous-pixel AVHRR
1340 !
1341 implicit none
1342
1343 ! Arguments:
1344 type (avhrr_bgck_iasi), intent(inout) :: avhrr
1345
1346 ! Locals:
1347 integer :: classIndex, channelIndex
1348 real(8) :: sumFrac(nvis+nir), sumBt(nvis+1:nvis+nir),sumBt2(nvis+1:nvis+nir)
1349 real(8) :: sumAlb(1:nvis),sumAlb2(1:nvis)
1350
1351 sumFrac(:) = 0.d0
1352 sumBt(:) = 0.d0
1353 sumBt2(:) = 0.d0
1354 sumAlb(:) = 0.d0
1355 sumAlb2(:) = 0.d0
1356
1357 do classIndex = 1, nClassAVHRR
1358 if (avhrr%cfrac(classIndex) > 0.d0 ) then
1359 do channelIndex = 1, NVIS
1360 if (avhrr%albedmoy(classIndex,channelIndex) >= 0.d0 ) then
1361 sumFrac(channelIndex) = sumFrac(channelIndex) + avhrr%cfrac(classIndex)
1362 sumAlb(channelIndex) = sumAlb(channelIndex) + avhrr%cfrac(classIndex) * avhrr%albedmoy(classIndex,channelIndex)
1363 sumAlb2(channelIndex) = sumAlb2(channelIndex) + avhrr%cfrac(classIndex) * ( avhrr%albedmoy(classIndex,channelIndex)**2 + avhrr%albedstd(classIndex,channelIndex)**2)
1364 end if
1365 end do
1366 do channelIndex = 1+NVIS, NVIS+NIR
1367 if (avhrr%tbmoy(classIndex,channelIndex) > 0.d0 ) then
1368 sumFrac(channelIndex) = sumFrac(channelIndex) + avhrr%cfrac(classIndex)
1369 sumBt(channelIndex) = sumBt(channelIndex) + avhrr%cfrac(classIndex) * avhrr%tbmoy(classIndex,channelIndex)
1370 sumBt2(channelIndex) = sumBt2(channelIndex) + avhrr%cfrac(classIndex) * (avhrr%tbmoy(classIndex,channelIndex)**2 + avhrr%tbstd(classIndex,channelIndex)**2 )
1371 end if
1372 end do
1373 end if
1374 end do
1375
1376 do channelIndex = 1, NVIS
1377 if (sumFrac(channelIndex) > 0.d0 ) then
1378 sumAlb(channelIndex) = sumAlb(channelIndex) / sumFrac(channelIndex)
1379 sumAlb2(channelIndex) = sumAlb2(channelIndex)/sumFrac(channelIndex) - sumAlb(channelIndex)**2
1380 if (sumAlb2(channelIndex) > 0.d0) then
1381 sumAlb2(channelIndex) = sqrt( sumAlb2(channelIndex) )
1382 else
1383 sumAlb2(channelIndex) = 0.d0
1384 end if
1385 end if
1386 end do
1387
1388 do channelIndex = NVIS+1, NVIS+NIR
1389 if (sumFrac(channelIndex) > 0.d0 ) then
1390 sumBt(channelIndex) = sumBt(channelIndex) / sumFrac(channelIndex)
1391 sumBt2(channelIndex) = sumBt2(channelIndex)/sumFrac(channelIndex) - sumBt(channelIndex)**2
1392 if (sumBt2(channelIndex) > 0.d0) then
1393 sumBt2(channelIndex)= sqrt ( sumBt2(channelIndex) )
1394 else
1395 sumBt2(channelIndex) = 0.d0
1396 end if
1397 end if
1398 end do
1399
1400 avhrr % tbstd_pixelIASI = sumBt2
1401 avhrr % albstd_pixeliasi = sumAlb2
1402
1403 end subroutine stat_avhrr
1404
1405 !--------------------------------------------------------------------------
1406 ! co2_slicing
1407 !--------------------------------------------------------------------------
1408 subroutine co2_slicing (ptop, ntop, fcloud, &
1409 rcal, cloudyRadiance, radObs, p0, plev, cldflag, rejflag, &
1410 lev_start, ichref, ilist, ilist_pair)
1411 !
1412 !:Purpose: cloud top height computation.
1413 ! cloud top from co2 slicing and cloud fraction estimate
1414 !
1415 implicit none
1416
1417 ! Arguments:
1418 real(8), intent(in) :: rcal(:) ! computed clear radiances (mW/m2/sr/cm-1)
1419 real(8), intent(in) :: plev(:) ! pressure levels (hPa)
1420 real(8), intent(in) :: cloudyRadiance(size(rcal),size(plev)) ! computed cloud radiances from each level (mW/m2/sr/cm-1)
1421 real(8), intent(in) :: radObs(size(rcal)) ! Observed radiances (mW/m2/sr/cm-1)
1422 real(8), intent(in) :: p0 ! surface pressure (hPa)
1423 integer, intent(in) :: ichref ! window channel to predetermine clear
1424 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1425 integer, intent(in) :: rejflag(1:,0:) ! flags for rejected observations
1426 integer, intent(in) :: ilist(nco2) ! first list of channels
1427 integer, intent(in) :: ilist_pair(nco2) ! second list channe
1428 integer, intent(inout) :: lev_start ! Level to start iteration (ideally tropopause)
1429 real(8), intent(out) :: ptop(nco2) ! Cloud top (hPa)
1430 real(8), intent(out) :: fcloud(nco2) ! Cloud fraction
1431 integer, intent(out) :: ntop(nco2) ! Nearest pressure level corresponding to ptop (ptop <= p0)
1432
1433 ! Locals
1434 integer :: j,jch,jc,jpmax,jmax, nlev,nchn
1435 integer :: sumrej
1436 real(8) :: rapg
1437 real(8),allocatable :: drap(:,:), a_drap(:), fc(:,:)
1438 real(8) :: val,val1,val2,val3,fcint
1439 real(8) :: emi_ratio
1440 integer :: jc_pair
1441 integer :: iter,niter
1442 real(8), parameter :: eps = 1.D-12
1443
1444 ptop(:) = -1.d0
1445 ntop(:) = -1
1446 fcloud(:) = -1.d0
1447
1448 ! Profile not assimilated if data from 2 windows channels bad
1449 ! and/or if data from 2 reference co2 channels bad
1450
1451 if ( cldflag == -1 ) return
1452
1453 nlev = size(plev)
1454 nchn = size(rcal)
1455
1456 ! Define closest level jpmax to surface pressure p0
1457
1458 jpmax = nlev
1459
1460 do J = lev_start, nlev
1461 if ( plev(J) > p0 ) then
1462 jpmax = J
1463 exit
1464 end if
1465 end do
1466
1467 ! define jmax as last level for co2-slicing calculations
1468
1469 jmax = jpmax - 1
1470
1471 ! predetermined clear window channel, all nco2 estimates clear
1472
1473 sumrej = sum(rejflag(ichref,:))
1474
1475 if ( sumrej == 0 ) then
1476 ptop(:) = p0
1477 ntop(:) = jpmax
1478 fcloud(:) = 0.d0
1479 return
1480 end if
1481
1482 allocate(fc(nchn,nlev), drap(nco2,nlev), a_drap(nlev) )
1483
1484 channels: do jch = 1, nco2
1485
1486 jc = ilist(jch)
1487 jc_pair = ilist_pair(jch)
1488 fc(jc_pair,:) = rcal(jc_pair) - cloudyRadiance(jc_pair,:)
1489 niter = 1
1490 if ( jch > 13) niter = 2
1491
1492 iteration: do iter = 1, niter
1493 drap(jch,:) = 9999.d0
1494 ntop(jch) = -1
1495 ! calcul emi_ratio
1496 if (jch > 13) then
1497 if ( iter == 1 ) then
1498 emi_ratio = 1.0376d0
1499 else
1500 emi_ratio = 1.09961d0 - 0.09082d0 * fcloud(jch)
1501 end if
1502 else
1503 emi_ratio = 1.0d0
1504 end if
1505
1506 fc(jc,:) = rcal(jc) - cloudyRadiance(jc,:)
1507
1508 ! Gross check failure
1509
1510 if ( rejflag(jc,9) == 1 ) cycle channels
1511 if ( rejflag(jc_pair,9) == 1 ) cycle channels
1512
1513 if ( abs( rcal(jc_pair) - radObs(jc_pair) ) > eps ) then
1514 rapg = (rcal(jc) - radObs(jc)) / (rcal(jc_pair) - radObs(jc_pair))
1515 else
1516 rapg = 0.0d0
1517 end if
1518
1519 do J = lev_start, jpmax
1520 if ( fc(jc,J) > 0.d0 .and. fc(jc_pair,J) > 0.d0 ) &
1521 drap(jch,J) = rapg - (fc(jc,J) / fc(jc_pair,J)) * emi_ratio
1522 end do
1523
1524 a_drap(:) = abs( drap(jch,:) )
1525
1526 levels: do J = lev_start + 1, jmax
1527
1528 ! * do not allow fc negative (i.e. drap(jch,j) = 9999.)
1529
1530 if ( drap(jch,J) > 9000.d0 .and. &
1531 a_drap(J-1) < eps .and. &
1532 a_drap(J+1) < eps ) cycle channels
1533
1534 val = drap(jch,J) / drap(jch,J - 1)
1535
1536 ! * find first, hopefully unique, zero crossing
1537
1538 if ( val < 0.d0 ) then
1539
1540 ! * conditions near zero crossing of isolated minimum need monotonically
1541 ! * decreasing drap from j-3 to j-1 as well increasing from j to j+1
1542
1543 val1 = drap(jch,J - 2) / drap(jch,J - 1)
1544 val2 = drap(jch,J - 3) / drap(jch,J - 1)
1545 val3 = drap(jch,J) / drap(jch,J + 1)
1546
1547 if ( val1 > 0.d0 .and. &
1548 val2 > 0.d0 .and. &
1549 val3 > 0.d0 .and. &
1550 a_drap(J-2) > a_drap(J-1) .and. &
1551 a_drap(J-3) > a_drap(J-2) .and. &
1552 a_drap(J) < 9000.d0 .and. &
1553 a_drap(J+1) > a_drap(J) ) &
1554 then
1555 ptop(jch) = plev(J)
1556 ntop(jch) = J
1557 end if
1558
1559 exit levels
1560
1561 end if
1562
1563 end do levels
1564
1565 j = ntop(jch)
1566
1567 ! * special cases of no determination
1568
1569 if ( j < 1) then
1570 ptop(jch) = -1.d0
1571 ntop(jch) = -1
1572 fcloud(jch) = -1.d0
1573 cycle channels
1574 end if
1575
1576 if ( J <= lev_start .or. drap(jch,J) > 9000.d0 ) then
1577 !if ( iter == 1) then
1578 ptop(jch) = -1.d0
1579 ntop(jch) = -1
1580 fcloud(jch) = -1.d0
1581 !end if
1582 cycle channels
1583 end if
1584
1585 if ( abs( cloudyRadiance(jc,J) - rcal(jc) ) > 0.d0 ) &
1586 fcloud(jch) = (radObs(jc) - rcal(jc)) / &
1587 (cloudyRadiance(jc,J) - rcal(jc))
1588
1589 ! * find passage to zero if it exists and interpolate to exact pressure
1590
1591 ptop(jch) = plev(J - 1) - drap(jch,J - 1) / &
1592 ( drap(jch,J) - drap(jch,J-1) ) * ( plev(J) - plev(J-1) )
1593 ! * find cloud radiance at zero crossing to use to get cloud fraction
1594
1595 fcint = fc(jc,J - 1) + ( fc(jc,J) - fc(jc,J - 1) ) / &
1596 ( plev(J) - plev(J - 1) ) * ( ptop(jch) - plev(J - 1) )
1597
1598 ! * find cloud fraction based on exact cloud top
1599
1600 if ( abs(fcint) > 0.d0 ) &
1601 fcloud(jch) = ( rcal(jc) - radObs(jc) ) / fcint
1602
1603 fcloud(jch) = min ( fcloud(jch), 1.5d0 )
1604 fcloud(jch) = max ( fcloud(jch), -0.5d0 )
1605
1606 if (fcloud(jch) < 0.0d0 .or. fcloud(jch) > 1.0d0 ) cycle channels
1607
1608 end do iteration
1609
1610 end do channels
1611
1612 deallocate(fc, drap, a_drap )
1613
1614 end subroutine co2_slicing
1615
1616 !--------------------------------------------------------------------------
1617 ! seltop
1618 !--------------------------------------------------------------------------
1619 subroutine seltop (etop, vtop, ecf, vcf, ngood, he, ht, cf, cfsub, ptop_mb, p0, cldflag, gncldflag)
1620 !
1621 !:Purpose: Select cloud top by averaging co2-slicing results
1622 ! judged correct. all missing values are -1.
1623 !
1624 implicit none
1625
1626 ! Arguments:
1627 real(8), intent(in) :: he ! equivalent cloud top heights from a window channel (hPa)
1628 real(8), intent(in) :: ht(nco2) ! cloud tops from co2-slicing (hPa)
1629 real(8), intent(in) :: cf(nco2) ! effective cloud fraction for co2-slicing
1630 real(8), intent(in) :: p0 ! surface pressure in (hPa)
1631 real(8), intent(in) :: cfsub ! visible ("subpixel") cloud fraction
1632 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1633 integer, intent(in) :: gncldflag! Garand Nadon cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1634 real(8), intent(out) :: etop ! consensus cloud top (hPa)
1635 real(8), intent(out) :: vtop ! corresponding variance on etop (hPa)
1636 real(8), intent(out) :: ecf ! consensus effective cloud fraction
1637 real(8), intent(out) :: vcf ! corresponding variance on ecf
1638 integer, intent(out) :: ngood ! number of good estimates
1639 real(8), intent(in) :: ptop_mb ! height (mb) from cloud_height subroutine
1640
1641 ! Locals:
1642 integer :: n,jch
1643 real(8) :: H(nco2),F(nco2)
1644
1645 etop = -1.d0
1646 vtop = -1.d0
1647 ecf = -1.d0
1648 vcf = -1.d0
1649 ngood = 0
1650
1651 ! Profile not assimilated if data from 2 windows channels bad
1652 ! and/or if data from 2 reference co2 channels bad
1653 if ( cldflag == -1 ) return
1654
1655 n = 0
1656 H(:) = 0.d0
1657 F(:) = 0.d0
1658
1659 do jch = 1, nco2
1660
1661 ! Check for zero cloud fraction
1662
1663 if ( CF(jch) > -0.9d0 .and. CF(jch) < 1.D-6 ) then
1664 n = n + 1
1665 H(n) = p0
1666 F(n) = 0.d0
1667 else
1668
1669
1670 ! Consider only valid values of cloud fraction above some threshold
1671
1672 ! Important logic: for values above 1.0 of co2-slicing cloud fraction,
1673 ! set it to 1.0 and force the top equal to the effective height he.
1674 ! co2-slicing not allowed to give estimates below he, which happens
1675 ! for cloud fraction cf > 1.0.
1676
1677 if ( ht(jch) > 0.0d0 ) then
1678 n = n + 1
1679 H(n) = ht(jch)
1680 F(n) = min(CF(jch), 1.0d0)
1681 F(n) = max(F(n), 0.d0)
1682 if ( CF(jch) > 1.0d0 ) H(n) = he
1683 end if
1684 end if
1685
1686 end do
1687
1688
1689 ngood = n
1690
1691 ! Compute mean and variance
1692
1693 if ( n >= 1 ) then
1694
1695 call calcul_median_fast(n,H,F,etop,ecf)
1696
1697 vtop = sqrt ( sum((H(1:n) - etop)**2) / n )
1698 vcf = sqrt ( sum((F(1:n) - ecf)**2) / n )
1699
1700 if ( n == 1 ) then
1701 vtop = 50.d0
1702 vcf = 0.20d0
1703 end if
1704
1705 else
1706
1707 ! If no solution from co2-slicing, and not predetermined clear,
1708 ! assume cloudy with top equal to effective height he;
1709 ! however if he is very close to surface pressure p0, assume clear.
1710
1711 etop = he
1712 ecf = 1.0d0
1713 if (cfsub >= 0.05d0) then
1714 ecf = cfsub
1715 etop = min( min(he,ptop_mb) , p0 - 50.0d0)
1716 end if
1717 vtop = 50.d0
1718 vcf = 0.30d0
1719 if ( he > (p0 - 10.d0) ) ecf = 0.d0
1720 if ( gncldflag == 0 ) then
1721 ecf = 0.0d0
1722 etop = p0
1723 end if
1724 end if
1725
1726 if ( ecf < 0.05d0 ) then
1727 ecf = 0.0d0
1728 etop = p0
1729 end if
1730
1731 end subroutine seltop
1732
1733 !--------------------------------------------------------------------------
1734 ! calcul_median_fast
1735 !--------------------------------------------------------------------------
1736 subroutine calcul_median_fast(nEstimates, Hin, Fin, ctp, cfr)
1737 !
1738 !:Purpose: Compute cloud fraction and height median.
1739 !
1740 !
1741 implicit none
1742
1743 ! Arguments:
1744 integer, intent(in) :: nEstimates ! Number of Co2 slicing estimates
1745 real(8), intent(in) :: Hin(:) ! Array of Height estimates
1746 real(8), intent(in) :: Fin(:) ! Array of Cloud fraction estimates
1747 real(8), intent(out) :: ctp ! Median of cloud top pressure estimates
1748 real(8), intent(out) :: cfr ! Corresponding cloud fraction
1749
1750 ! Locals:
1751 integer :: index(nEstimates)
1752 real(4) :: H(nEstimates)
1753 integer :: i
1754
1755 if (nEstimates == 1) then
1756 ctp = Hin(nEstimates)
1757 cfr = Fin(nEstimates)
1758 else
1759 H(1:nEstimates) = Hin(1:nEstimates)
1760 call IPSORT(index,H,nEstimates)
1761 if (mod(nEstimates,2) == 0) then ! N - pair
1762 i = index(nEstimates / 2)
1763 else ! N - impair
1764 i = index(1 + nEstimates / 2)
1765 end if
1766 ctp = Hin(i)
1767 cfr = Fin(i)
1768 end if
1769
1770 end subroutine calcul_median_fast
1771
1772 !--------------------------------------------------------------------------
1773 ! min_pres_new
1774 !--------------------------------------------------------------------------
1775 subroutine min_pres_new( maxheight, minp, pmin, dt1, p0, tau, plev, cldflag, &
1776 modelTopIndex )
1777 !
1778 !:Purpose: from total transmittance array, find minimum height
1779 ! level of sensitivity for a number of profiles and channels.
1780 ! this may be used to select for assimilation only the
1781 ! observations without sensitivity to clouds, that is the
1782 ! response function significant only above cloud level.
1783 ! the criterion is that dtau/dplev > 0.01 for a 100 mb layer.
1784 !
1785 !
1786 implicit none
1787
1788 ! Arguments:
1789 real(8), intent(out) :: maxHeight(:) ! Height (hPa) of the maximum of the weighting function
1790 integer, intent(out) :: minp(size(maxHeight)) ! vertical level corresponding to pmin
1791 real(8), intent(out) :: pmin(size(maxHeight)) ! minimum height of sensitivity (hPa)
1792 real(8), intent(out) :: dt1(size(maxHeight)) ! value of 'dtau/dlogp' at model top
1793 real(8), intent(in) :: p0 ! surface pressure (hPa)
1794 real(8), intent(in) :: plev(:) ! pressure levels (hPa)
1795 real(8), intent(in) :: tau(size(maxHeight),size(plev)) ! layer to space transmittances (0.-1.)
1796 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1797 integer, intent(in) :: modelTopIndex ! rt model level nearest to model top
1798
1799 ! Locals:
1800 real(8) :: maxwf
1801 integer :: levelIndex, channelIndex, ipos(1), nlev, nchn
1802 real(8),allocatable :: wfunc(:), rap(:)
1803
1804 minp(:) = -1
1805 pmin(:) = -1.d0
1806 dt1(:) = -1.d0
1807
1808 if ( cldflag == -1 ) return
1809
1810 nlev = size(plev)
1811 nchn = size(maxHeight)
1812
1813 allocate( wfunc(nlev-1), rap(nlev-1) )
1814
1815 do levelIndex = 1, nlev - 1
1816 rap(levelIndex) = log( plev(levelIndex + 1) / plev(levelIndex) )
1817 end do
1818
1819 channels: do channelIndex = 1, nchn
1820
1821 ! Profile not assimilated if data from 2 windows channels bad
1822 ! and/or if data from 2 reference co2 channels bad
1823
1824 do levelIndex = 1, nlev
1825 if ( tau(channelIndex,levelIndex) < 0.d0) cycle channels
1826 end do
1827
1828 minp(channelIndex) = nlev
1829 pmin(channelIndex) = min(plev(nlev),p0)
1830
1831 ! Compute entire array of dtau/dlog(P)
1832
1833 do levelIndex = 1, nlev - 1
1834 wfunc(levelIndex) = (tau(channelIndex,levelIndex) - tau(channelIndex,levelIndex + 1)) / rap(levelIndex)
1835 end do
1836
1837 dt1(channelIndex) = wfunc(modelTopIndex)
1838
1839 ! If channel sees the surface, don't recalculate minp and pmin
1840
1841 if ( tau(channelIndex,nlev) > 0.01d0 ) cycle channels
1842
1843 ! Recherche du maximum
1844 ipos = maxloc( wfunc(:) )
1845 ! Calcul de la valeur du maximum
1846 maxwf = wfunc(ipos(1))
1847 ! maximum entre les 2 niveaux puisque WF calculee pour une couche finie ( discutable ?)
1848 maxheight(channelIndex)= 0.5d0 * ( plev(ipos(1)) + plev(ipos(1) + 1) )
1849
1850 ! If channel doesn't see the surface, see where dtau/dlog(plev) becomes important
1851 ! for recomputation of minp and pmin.
1852
1853 do levelIndex = nlev - 1, ipos(1), -1
1854 if ( ( wfunc(levelIndex)/ maxwf ) > 0.01d0) then
1855 minp(channelIndex) = levelIndex + 1
1856 pmin(channelIndex) = min(plev(levelIndex + 1),p0)
1857 exit
1858 end if
1859 end do
1860
1861 end do channels
1862
1863 deallocate(wfunc, rap )
1864
1865 end subroutine min_pres_new
1866
1867 !--------------------------------------------------------------------------
1868 ! cloud_height
1869 !--------------------------------------------------------------------------
1870 subroutine cloud_height ( ptop, ntop, btObs, cldflag, tt, height, p0, plev, &
1871 ichref, lev_start, iopt )
1872 !
1873 !:Purpose:
1874 ! Computation of cloud top height (above the ground)
1875 ! based on matching observed brightness temperature at a
1876 ! reference surface channel with background temperature profile.
1877 ! to use with one reference channel. used here on model levels.
1878 !
1879 implicit none
1880
1881 ! Arguments:
1882 real(8), intent(out) :: ptop ! Chosen equivalent cloud tops (in hpa|m with iopt = 1|2)
1883 integer, intent(out) :: ntop ! Number of possible ptop solutions
1884 real(8), intent(in) :: btObs(:) ! Observed brightness temperature (deg k)
1885 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1886 real(8), intent(in) :: tt(:) ! Temperature profiles (deg K)
1887 real(8), intent(in) :: height(size(tt))! Height profiles above ground (m)
1888 real(8), intent(in) :: p0 ! Surface pressure (hPa)
1889 real(8), intent(in) :: plev(size(tt)) ! Pressure levels (hPa)
1890 integer, intent(in) :: ichref ! Chosen reference surface channel
1891 integer, intent(inout) :: lev_start ! Level to start iteration (ideally tropopause)
1892 integer, intent(in) :: iopt ! Levels using plev (1) or height (2)
1893
1894 ! Locals:
1895 integer :: itop
1896 integer :: nht, nlev
1897 real(8), allocatable :: ht(:)
1898
1899 nlev = size(tt)
1900 allocate(ht(nlev))
1901
1902 if ( iopt == 1 ) then
1903
1904 ptop = p0
1905 ntop = 1
1906
1907 if ( cldflag == -1 ) return
1908
1909 call get_top ( ht, nht, btObs(ichref), tt, plev, lev_start, iopt )
1910
1911 itop = 1
1912 if ( nht >= 2 ) itop = 2
1913 ptop = min ( ht(itop), p0 )
1914 ntop = nht
1915
1916 else if ( iopt == 2 ) then
1917
1918 ptop = 0.d0
1919 ntop = 1
1920
1921 if ( cldflag == -1 ) return
1922
1923 call get_top ( ht,nht, btObs(ichref),tt,height,lev_start,iopt )
1924
1925 itop = 1
1926 if ( nht >= 2 ) itop = 2
1927 ptop = max ( ht(itop), 0.d0 )
1928 ntop = nht
1929
1930 end if
1931
1932 deallocate(ht)
1933
1934 end subroutine cloud_height
1935
1936 !--------------------------------------------------------------------------
1937 ! garand1998nadon
1938 !--------------------------------------------------------------------------
1939 subroutine garand1998nadon ( cldflag, btObs, tg, tt, height, &
1940 ptop_eq, ntop_eq, ichref )
1941 !
1942 !:Purpose: Determine if the profiles are clear or cloudy based on
1943 ! the algorithm of garand & nadon 98 j.clim v11 pp.1976-1996
1944 ! with channel iref.
1945 implicit none
1946
1947 ! Arguments:
1948 integer, intent(inout) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
1949 real(8), intent(in) :: btObs(:) ! Observed brightness temperatures (K)
1950 real(8), intent(in) :: tg ! Guess skin temperatures (K)
1951 real(8), intent(in) :: tt(:) ! Guess temperature profiles (K)
1952 real(8), intent(in) :: height(size(tt))! Guess height profile above ground (m)
1953 real(8), intent(in) :: ptop_eq ! Chosen equivalent cloud tops (m)
1954 integer, intent(in) :: ntop_eq ! Number of possible ptop_eq solutions
1955 integer, intent(in) :: ichref ! Chosen reference surface channel
1956
1957 ! Locals:
1958 integer :: ninv
1959 real(8) :: lev(2)
1960
1961 lev(1) = 222.d0
1962 lev(2) = 428.d0
1963
1964 if ( cldflag == -1 ) return
1965
1966 if ( btObs(ichref) >= tg - 3.d0 .and. btObs(ichref) <= tg + 3.d0 ) then
1967 cldflag = 0
1968 return
1969 end if
1970
1971 if ( btObs(ichref) >= tg - 4.d0 .and. btObs(ichref) <= tg - 3.d0 ) then
1972 if ( ptop_eq > 1100.d0 ) then
1973 cldflag = 1
1974 return
1975 else
1976 cldflag = 0
1977 return
1978 end if
1979 end if
1980
1981 if ( ptop_eq > 728.d0 ) then
1982 cldflag = 1
1983 return
1984 end if
1985
1986 if ( tg - btObs(ichref) > 8.d0 ) then
1987 if ( ntop_eq >= 3 ) then
1988 if ( ptop_eq > 73.d0 ) then
1989 cldflag=1
1990 return
1991 else
1992 cldflag=0
1993 return
1994 end if
1995 else
1996 call monotonic_inversion (ninv, tg,tt,height,lev(1))
1997 if ( ninv == 1 ) then
1998 if ( ptop_eq > 222.d0 ) then
1999 cldflag = 1
2000 return
2001 else
2002 cldflag = 0
2003 return
2004 end if
2005 else
2006 cldflag = 0
2007 return
2008 end if
2009 end if
2010 end if
2011
2012 if ( tg - btObs(ichref) > 5.d0 ) then
2013 if ( ntop_eq >= 3 ) then
2014 if ( ptop_eq > 222.d0 ) then
2015 cldflag = 1
2016 return
2017 else
2018 cldflag = 0
2019 return
2020 end if
2021 else
2022 call monotonic_inversion (ninv, tg,tt,height,lev(2))
2023 if ( ninv == 1) then
2024 if( ptop_eq > 428.d0 ) then
2025 cldflag = 1
2026 return
2027 else
2028 cldflag = 0
2029 return
2030 end if
2031 else
2032 cldflag = 0
2033 end if
2034 end if
2035 else
2036 cldflag = 0
2037 end if
2038
2039 end subroutine garand1998nadon
2040
2041 !--------------------------------------------------------------------------
2042 ! monotonic_inversion
2043 !--------------------------------------------------------------------------
2044 subroutine monotonic_inversion ( ninvr, tg, tt, height, lvl )
2045 !
2046 !:Purpose: Determine if there is a presence (ninvr=1) or not (ninvr=0)
2047 ! of a temperature inversion going from the surface up to the
2048 ! height lvl
2049 !
2050 !:Arguments:
2051 ! :ninvr: PRESENCE (1) OR NOT (0) OF A TEMPERATURE INVERSION
2052 ! FROM THE SURFACE TO HEIGHT LVL
2053 !
2054 implicit none
2055
2056 ! Arguments:
2057 real(8), intent(in) :: tt(:) ! Temperature profile (K)
2058 real(8), intent(in) :: height(size(tt))! Height profile above ground (m)
2059 real(8), intent(in) :: tg ! Skin temperature (K)
2060 real(8), intent(in) :: lvl ! Height to search for temperature inversion (m)
2061 integer, intent(out) :: ninvr ! Number of inversions
2062
2063 ! Locals:
2064 integer :: levelIndex, nlevels
2065
2066 ninvr = 0
2067 nlevels = size ( tt )
2068 if ( tg - tt(nlevels) < 0.d0 ) then
2069 ninvr = 1
2070 do levelIndex = nlevels - 1, 1, -1
2071 if ( height(levelIndex) > lvl ) exit
2072 if ( tt(levelIndex+1) - tt(levelIndex) > 0.d0 ) then
2073 ninvr = 0
2074 exit
2075 end if
2076 end do
2077 end if
2078
2079 end subroutine monotonic_inversion
2080
2081
2082 !--------------------------------------------------------------------------
2083 ! estim_ts
2084 !--------------------------------------------------------------------------
2085 subroutine estim_ts( ts, tg, emi, rcal, radobs, sfctau, cldflag, &
2086 ichref, myCoefs )
2087 !
2088 !:Purpose: Get an estimated skin temperature by inversion of
2089 ! radiative transfer equation assuming guess t and q profiles
2090 ! are perfect. designed for a single channel ichref and nprf
2091 ! profiles. assumes a real tg (guess) over oceans and a tg
2092 ! with hypothesis of unity emissivity over land.
2093 !
2094 !:Note: Uses rcal = B(TG)*EMI*SFCtau + ATMOS_PART
2095 ! ts = B(ts)*EMI*SFCtau + ATMOS_PART
2096 ! SOLVES FOR ts
2097 !
2098 implicit none
2099
2100 ! Arguments:
2101 integer, intent(in) :: ichref ! Reference surface channel (subset values)
2102 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
2103 real(8), intent(in) :: tg ! Guess skin temperature (K)
2104 real(8), intent(in) :: emi(:) ! Surface emissivities from window channel (0.-1.)
2105 real(8), intent(in) :: rcal(size(emi)) ! Computed clear radiances (mW/m2/sr/cm-1)
2106 real(8), intent(in) :: radobs(size(emi)) ! Observed radiances (mW/m2/sr/cm-1)
2107 real(8), intent(in) :: sfctau(size(emi)) ! Surface to space transmittances (0.-1.)
2108 real(8), intent(out) :: ts ! Retrieved skin temperature (-1. for missing)
2109 type(rttov_coefs), intent(in) :: myCoefs ! RTTOV coefficients structure
2110
2111 ! Locals:
2112 real(8) :: rtg,radtg
2113 real(8) :: radts,tstore,t_effective
2114
2115 ts = -1.d0
2116
2117 if ( cldflag /= 0 ) return
2118 if ( ichref == -1 ) return
2119
2120
2121 ! Transform guess skin temperature to plank radiances
2122
2123 t_effective = myCoefs % coef % ff_bco(ichref) + myCoefs % coef % ff_bcs(ichref) * TG
2124
2125 radtg = myCoefs % coef % planck1(ichref) / &
2126 ( exp( myCoefs % coef % planck2(ichref) / t_effective ) - 1.0d0 )
2127
2128
2129 ! Compute TOA planck radiances due to guess skin planck radiances
2130
2131 rtg = radtg * EMI(ichref) * SFCtau(ichref)
2132
2133
2134 ! Compute true skin planck radiances due to TOA true planck radiances
2135
2136 radts = ( RADOBS(ichref) + rtg - rcal(ichref) ) / &
2137 ( EMI(ichref) * SFCtau(ichref) )
2138
2139 if (radts <= 0.d0) then
2140 write(*,'(A25,1x,8e14.6)') "Warning, negative radts", RADOBS(ichref), rtg, rcal(ichref), EMI(ichref), SFCtau(ichref), &
2141 ( RADOBS(ichref) + rtg - rcal(ichref) ), ( EMI(ichref) * SFCtau(ichref) ), radts
2142 write(*,*) "Skipping tskin retrieval."
2143 return
2144 end if
2145
2146
2147 ! Transform true skin planck radiances to true skin temperatures
2148
2149 tstore = myCoefs % coef % planck2(ichref) / log( 1.0d0 + myCoefs % coef % planck1(ichref) / radts )
2150
2151 ts = ( tstore - myCoefs % coef % ff_bco(ichref) ) / myCoefs % coef % ff_bcs(ichref)
2152
2153
2154 end subroutine estim_ts
2155
2156 !--------------------------------------------------------------------------
2157 ! cloud_top
2158 !--------------------------------------------------------------------------
2159 subroutine cloud_top ( ptop_bt, ptop_rd, ntop_bt, ntop_rd, btObs, &
2160 tt, height, rcal, p0, radObs, cloudyRadiance, plev, &
2161 cldflag, lev_start, iopt, ihgt, &
2162 ilist,rejflag_opt, ichref_opt )
2163 !
2164 !:Purpose: Computation of cloud top height (above the ground)
2165 ! based on matching observed brightness temperature with
2166 ! background temperature profiles and/or computed observed
2167 ! radiances with background radiance profiles.
2168 ! to use with more than one channel. used here on rttov levels.
2169 !
2170 !
2171 implicit none
2172
2173 ! Arguments:
2174 real(8), intent(out) :: ptop_bt(:) ! Chosen equivalent cloud tops based on brightness temperatures (in hpa|m with iopt = 1|2)
2175 real(8), intent(out) :: ptop_rd(:) ! Chosen equivalent cloud tops based on radiances (in hpa|m with iopt = 1|2)
2176 integer, intent(out) :: ntop_bt(:) ! Number of possible ptop_bt solutions
2177 integer, intent(out) :: ntop_rd(:) ! Number of possible ptop_rd solutions
2178 real(8), intent(in) :: btObs(:) ! Observed brightness temperautres (K)
2179 real(8), intent(in) :: tt(:) ! Temperature profiles (K)
2180 real(8), intent(in) :: height(:) ! Height profiles above ground (m)
2181 real(8), intent(in) :: rcal(:) ! Computed clear radiances (mW/m2/sr/cm-1)
2182 real(8), intent(in) :: p0 ! Surface pressure (hPa)
2183 real(8), intent(in) :: radObs(:) ! Computed observed radiances (mW/m2/sr/cm-1)
2184 real(8), intent(in) :: cloudyRadiance(:,:) ! Computed cloud radiances from each level (hPa)
2185 real(8), intent(in) :: plev(:) ! Pressure levels (hPa)
2186 integer, intent(in) :: cldflag ! Cloudy flag (0 Clear, 1 Cloudy, -1 undefined)
2187 integer, intent(inout) :: lev_start ! Level to start iteration (ideally tropopause)
2188 integer, intent(in) :: iopt ! Levels using plev (1) or height (2)
2189 integer, intent(in) :: ihgt ! Get *_bt* only (0), *_rd* only (1), both (2)
2190 integer, intent(in) :: ilist(:) ! List of the channel numbers (subset values)
2191 integer, optional, intent(in) :: rejflag_opt(1:,0:)! Flags for rejected observations
2192 integer, optional, intent(in) :: ichref_opt ! Reference surface channel (subset value)
2193
2194 ! Locals:
2195 integer :: jch,jc,itop,nht,i10,i,nlev,nch
2196 real(8),allocatable :: ht(:)
2197 logical :: clear, cloudy
2198
2199 ! Profile not assimilated if data from 2 windows channels bad
2200
2201 ptop_bt(:) = -10.d0
2202 ptop_rd(:) = -10.d0
2203 ntop_bt(:) = 0.d0
2204 ntop_rd(:) = 0.d0
2205
2206 if ( cldflag == -1 ) return
2207
2208 nlev = size( tt )
2209 i10=1
2210 do i=2, nlev
2211 if (plev(i - 1) <= 100.d0 .and. plev(i) > 100.d0) then
2212 i10 = i
2213 exit
2214 end if
2215 end do
2216
2217 ! predetermined clear
2218 if ( present(rejflag_opt)) then
2219 clear = ( sum( rejflag_opt(ichref_opt,:) ) == 0 )
2220 else
2221 clear = ( cldflag == 0 )
2222 end if
2223
2224 if ( clear ) then
2225
2226 if ( iopt == 1 ) then
2227 ptop_bt(:) = min ( plev(nlev), p0 )
2228 ptop_rd(:) = min ( plev(nlev), p0 )
2229 else if ( iopt == 2 ) then
2230 ptop_bt(:) = 0.d0
2231 ptop_rd(:) = 0.d0
2232 end if
2233
2234 ntop_bt(:) = 1
2235 ntop_rd(:) = 1
2236
2237 lev_start = max ( lev_start , i10 )
2238
2239 return
2240
2241 end if
2242
2243 allocate ( ht(nlev) )
2244 nch = size( ilist)
2245
2246 channels: do jch = 1, nch
2247
2248 jc = ilist(jch)
2249
2250 ! missing channel ... yes it can happen
2251 if (jc == -1) cycle channels
2252 ! gross check failure
2253 if ( present(rejflag_opt) ) then
2254 if ( rejflag_opt(jc,9) == 1 ) cycle channels
2255 else
2256 if ( btObs(jc) < 150.d0 .or. btObs(jc) > 350.d0) cycle channels
2257 end if
2258 ! no clouds if observed radiance warmer than clear estimate
2259
2260 if ( radObs(jc) > rcal(jc) ) then
2261
2262 if ( iopt == 1 ) then
2263 ptop_bt(jc) = min ( plev(nlev), p0 )
2264 ptop_rd(jc) = min ( plev(nlev), p0 )
2265 else if ( iopt == 2 ) then
2266 ptop_bt(jc) = 0.d0
2267 ptop_rd(jc) = 0.d0
2268 end if
2269
2270 ntop_bt(jc) = 1
2271 ntop_rd(jc) = 1
2272
2273 cycle channels
2274
2275 end if
2276
2277 ! cloudy
2278
2279 if ( present(rejflag_opt)) then
2280 cloudy = ( rejflag_opt(jc,11) == 1 .and. rejflag_opt(jc,23) == 1 )
2281 else
2282 cloudy = ( cldflag == 1 )
2283 end if
2284
2285 if ( cloudy ) then
2286
2287 if ( iopt == 1 ) then
2288
2289 if ( ihgt == 0 .or. ihgt == 2 ) then
2290 call get_top ( ht,nht, btObs(jc), tt, plev, lev_start, iopt )
2291 itop = 1
2292 if ( nht >= 2 ) itop = 2
2293 ptop_bt(jc) = min ( ht(itop), p0 )
2294 ntop_bt(jc) = nht
2295 end if
2296
2297 if ( ihgt == 1 .or. ihgt == 2 ) then
2298 call get_top ( ht, nht, radObs(jc), cloudyRadiance(jc,:), plev, lev_start, iopt )
2299 itop = 1
2300 if ( nht >= 2 ) itop = 2
2301 ptop_rd(jc) = min ( ht(itop), p0 )
2302 ntop_rd(jc) = nht
2303 end if
2304
2305 else if ( iopt == 2 ) then
2306
2307 if ( ihgt == 0 .or. ihgt == 2 ) then
2308 call get_top ( ht,nht, btObs(jc),tt,height,lev_start,iopt)
2309 itop = 1
2310 if ( nht >= 2 ) itop = 2
2311 ptop_bt(jc) = max ( ht(itop), 0.d0 )
2312 ntop_bt(jc) = nht
2313 end if
2314
2315 if ( ihgt == 1 .or. ihgt == 2 ) then
2316 call get_top ( ht,nht, radObs(jc),cloudyRadiance(jc,:),height,lev_start,iopt)
2317 itop = 1
2318 if ( nht >= 2 ) itop = 2
2319 ptop_rd(jc) = max ( ht(itop), 0.d0 )
2320 ntop_rd(jc) = nht
2321 end if
2322
2323 end if
2324
2325 end if
2326
2327 end do channels
2328
2329 deallocate ( ht )
2330
2331 end subroutine cloud_top
2332
2333 !--------------------------------------------------------------------------
2334 ! get_top
2335 !--------------------------------------------------------------------------
2336 subroutine get_top (ht, nht, bt, tt ,pp, lev_start, iopt)
2337 !
2338 !:Purpose: Computation of cloud top height and number of possible heights.
2339 !
2340 implicit none
2341
2342 ! Arguments:
2343 real(8), intent(out) :: ht(:) ! Cloud top height in hpa or meters (iopt = 1 or 2)
2344 integer, intent(out) :: nht ! Number of possible cloud height solutions
2345 real(8), intent(in) :: bt ! Observed brightness temperatures (deg k) or radiance (mw/m2/sr/cm-1)
2346 real(8), intent(in) :: tt(:) ! Temperature profile (deg k) or computed cloud radiance from each level to top
2347 real(8), intent(in) :: pp(size(tt)) ! Pressure (hpa) or heights (m) profile (iopt=1 or 2)
2348 integer, intent(inout) :: lev_start ! Level to start iteration (ideally tropopause, if <= 0, search & start at coldest level)
2349 integer, intent(in) :: iopt ! Height units in hpa (1) or in meters (2)
2350
2351 ! Locals:
2352 integer :: i, im(1), i10, nlev
2353 real(8),allocatable :: logp(:)
2354 real(8) :: dt, a, b
2355
2356 ht(:) = -1.
2357
2358 im = lev_start
2359
2360 nlev = size( tt )
2361
2362 if ( lev_start <= 0 ) then
2363
2364 ! Search index im(1) where tt is minimum
2365 im = minloc ( tt )
2366
2367 i10 = -1
2368 do i = 2, nlev
2369 if (pp(i-1) <= 100.d0 .and. pp(i) > 100.d0) then
2370 I10 = I
2371 exit
2372 end if
2373 end do
2374
2375 lev_start = im(1)
2376
2377 if ( im(1) == nlev ) then
2378 lev_start = max(lev_start,i10)
2379 nht = 1
2380 ht(1) = pp(nlev)
2381 return
2382 end if
2383
2384 end if
2385
2386 if (iopt == 1) then
2387 allocate ( logp(nlev) )
2388 logp(:) = log(pp(:))
2389 end if
2390
2391 nht = 0
2392
2393 do I = im(1), nlev - 1
2394 dt = tt(I + 1) - tt(I) + 1.D-12
2395 if ( bt > tt(I) .and. bt <= tt(I + 1) ) then
2396
2397 nht = nht + 1
2398
2399 if (iopt == 1) then
2400 a = logp(I) + (logp(I + 1) - logp(I)) / dt * ( bt - tt(I))
2401 ht(nht) = exp(a)
2402 end if
2403
2404 if (iopt == 2) then
2405 b = pp(I) + (pp(I+1) - pp(I)) / dt * (bt - tt(I))
2406 ht(nht) = b
2407 end if
2408
2409 else if ( bt >= tt(I+1) .and. bt < tt(I) ) then
2410
2411 nht = nht + 1
2412
2413 if (iopt == 1) then
2414 a = logp(I + 1)- (logp(I + 1)-logp(I)) / dt * (tt(I + 1) - bt)
2415 ht(nht) = exp(A)
2416 end if
2417
2418 if(iopt == 2) then
2419 b = pp(I + 1)- (pp(I + 1) - pp(I)) / dt * (tt(I + 1) - bt)
2420 ht(nht) = b
2421 end if
2422
2423 end if
2424 end do
2425
2426
2427 if ( nht == 0 .and. bt < tt(im(1)) ) then
2428 nht = 1
2429 ht(1) = pp(im(1))
2430 else if ( nht == 0 .and. bt > tt(nlev) ) then
2431 nht = 1
2432 ht(1) = pp(nlev)
2433 end if
2434
2435 if (iopt==1) deallocate ( logp )
2436
2437 end subroutine get_top
2438
2439 !--------------------------------------------------------------------------
2440 ! get_avhrr_emiss
2441 !--------------------------------------------------------------------------
2442 subroutine get_avhrr_emiss( iasi_surfem1, freqiasi, nchaniasi, avhrr_surfem1 )
2443 !
2444 !:Purpose: choisi l'emissivite d'un canal IASI proche pour AVHRR
2445 ! a raffiner pour prendre en compte la largeur des canaux AVHRR ??
2446 !
2447 implicit none
2448
2449 ! Arguments:
2450 real(8), intent(in) :: iasi_surfem1(nchaniasi)! IASI emissivities
2451 real(8), intent(in) :: freqiasi(nchaniasi) ! IASI wavenumbers (cm-1)
2452 integer, intent(in) :: nchaniasi ! Number of IASI channels
2453 real(8), intent(out) :: avhrr_surfem1(NIR) ! AVHRR emissivities
2454
2455 ! Locals:
2456 real(8),parameter :: freqavhrr(NIR)= (/0.2687000000D+04 , 0.9272000000D+03 , 0.8377000000D+03/)
2457 integer :: indxavhrr(NIR)
2458 integer :: i, pos(1)
2459
2460 do I=1,NIR
2461 pos = minloc ( abs (freqiasi(:) - freqavhrr(I)) )
2462 indxavhrr(i) = pos(1)
2463 end do
2464
2465 do I=1,NIR
2466 avhrr_surfem1(i) = iasi_surfem1(indxavhrr(i))
2467 end do
2468
2469 end subroutine get_avhrr_emiss
2470
2471 !--------------------------------------------------------------------------
2472 ! tovs_rttov_avhrr_for_IASI
2473 !--------------------------------------------------------------------------
2474 subroutine tovs_rttov_avhrr_for_IASI (headerIndex, surfem1_avhrr, idiasi)
2475 !
2476 !:Purpose: Computation of forward radiance with rttov_direct
2477 ! (for AVHRR).
2478 ! appel de RTTOV pour le calcul des radiances AVHRR
2479 ! (non assimilees mais necessaires au background check IASI)
2480 !
2481 implicit none
2482
2483 ! Arguments:
2484 integer, intent(in) :: headerIndex ! Location of IASI observation in TOVS structures and obSpaceData
2485 real(8), intent(in) :: surfem1_avhrr(3) ! AHVRR surface emissivities
2486 integer, intent(in) :: idiasi ! iasi (in fact METOP) number
2487
2488 ! Locals:
2489 type (rttov_profile), pointer :: profiles(:)
2490 type (rttov_chanprof) :: chanprof(3)
2491 logical :: calcemis (3)
2492 integer :: list_sensor (3),errorstatus,allocStatus
2493 integer, save :: idiasi_old=-1
2494 integer :: ich
2495 integer :: ichan_avhrr (NIR)
2496 type (rttov_transmission) :: transmission
2497 type (rttov_radiance) :: radiancedata_d
2498 type (rttov_emissivity) :: emissivity(3)
2499 integer :: nchannels
2500 integer :: nlevels, iptobs(1)
2501
2502 if (idiasi_old /= idiasi) then
2503 list_sensor(1) = 10
2504 list_sensor(2) = idiasi
2505 list_sensor(3) = 5
2506 do ich=1,nir
2507 ichan_avhrr(ich)=ich
2508 end do
2509
2510 errorstatus = 0
2511
2512 if (idiasi_old > 0) then
2513 call rttov_dealloc_coefs(errorstatus, coefs_avhrr )
2514 if ( errorstatus /= 0) then
2515 write(*,*) "Probleme dans rttov_dealloc_coefs !"
2516 call utl_abort("tovs_rttov_avhrr_for_IASI")
2517 end if
2518 end if
2519
2520 call rttov_read_coefs ( errorstatus, &! out
2521 coefs_avhrr, &! out
2522 tvs_opts(1), &! in
2523 channels=ichan_avhrr, &! in
2524 instrument=list_sensor ) ! in
2525
2526 if ( errorstatus /= 0) then
2527 write(*,*) "Probleme dans rttov_read_coefs !"
2528 call utl_abort("tovs_rttov_avhrr_for_IASI")
2529 end if
2530
2531 idiasi_old = idiasi
2532
2533 end if
2534
2535 call tvs_getProfile(profiles, 'nl')
2536
2537 iptobs(1) = headerIndex
2538 nlevels = profiles(headerIndex)% nlevels
2539
2540 nchannels = NIR
2541
2542 calcemis(:) = .false.
2543 emissivity(1:3)%emis_in = surfem1_avhrr(1:3)
2544 ! Build the list of channels/profiles indices
2545
2546 do ich = 1, nchannels
2547 chanprof(ich) % prof = 1
2548 chanprof(ich) % chan = ich
2549 end do
2550
2551 allocStatus = 0
2552 call rttov_alloc_direct( &
2553 allocStatus, &
2554 asw=1, &
2555 nprofiles=1, & ! (not used)
2556 nchanprof=nchannels, &
2557 nlevels=nlevels, &
2558 opts=tvs_opts(1), &
2559 coefs=coefs_avhrr, &
2560 transmission=transmission, &
2561 radiance=radiancedata_d, &
2562 init=.true.)
2563
2564 if (allocStatus /= 0) then
2565 write(*,*) "Memory allocation error"
2566 call utl_abort('tovs_rttov_avhrr_for_IASI')
2567 end if
2568
2569
2570 call rttov_direct( &
2571 errorstatus, & ! out
2572 chanprof, & ! in
2573 tvs_opts(1), & ! in
2574 profiles(iptobs(:)), & ! in
2575 coefs_avhrr, & ! in
2576 transmission, & ! inout
2577 radiancedata_d, & ! out
2578 calcemis=calcemis, & ! in
2579 emissivity=emissivity) ! inout
2580
2581 avhrr_bgck(headerIndex)% radclearcalc(NVIS+1:NVIS+NIR) = radiancedata_d % clear(1:NIR)
2582 avhrr_bgck(headerIndex)% tbclearcalc(NVIS+1:NVIS+NIR) = radiancedata_d % bt(1:NIR)
2583 allocate( avhrr_bgck(headerIndex)% radovcalc(nlevels-1,NVIS+1:NVIS+NIR) )
2584 avhrr_bgck(headerIndex)% radovcalc(1:nlevels-1,NVIS+1:NVIS+NIR) = radiancedata_d % overcast(1:nlevels-1,1:NIR)
2585 avhrr_bgck(headerIndex)% emiss(NVIS+1:NVIS+NIR) = emissivity(1:NIR)%emis_out
2586 avhrr_bgck(headerIndex)% transmsurf(NVIS+1:NVIS+NIR) = transmission% tau_total(1:NIR)
2587
2588
2589 call rttov_alloc_direct( &
2590 allocStatus, &
2591 asw=0, &
2592 nprofiles=1, & ! (not used)
2593 nchanprof=nchannels, &
2594 nlevels=nlevels, &
2595 opts=tvs_opts(1), &
2596 coefs=coefs_avhrr, &
2597 transmission=transmission, &
2598 radiance=radiancedata_d )
2599
2600 if (allocStatus /= 0) then
2601 write(*,*) "Memory deallocation error"
2602 call utl_abort('tovs_rttov_avhrr_for_IASI')
2603 end if
2604
2605 nullify(profiles)
2606
2607 end subroutine tovs_rttov_avhrr_for_IASI
2608
2609 !--------------------------------------------------------------------------
2610 ! cor_albedo
2611 !--------------------------------------------------------------------------
2612 subroutine cor_albedo(delta, scos)
2613 !
2614 !:Purpose: ce sous-programme calcule un facteur de correction
2615 ! pour l'albedo a partir du cosinus de l'angle solaire.
2616 !
2617 implicit none
2618
2619 ! Arguments:
2620 real(8), intent(in) :: scos ! Cosine of solar zenith angle
2621 real(8), intent(out) :: delta ! Correction factor
2622
2623 ! Locals:
2624 integer i1, i2, ierr
2625 real(8) x1, x2, g1, g2, a, b
2626 real(8),parameter :: s(11)=(/00.00d0, 18.19d0, 31.79d0, 41.41d0, 49.46d0, &
2627 56.63d0, 63.26d0, 69.51d0, 75.52d0, 81.37d0, 87.13d0/)
2628
2629 i1 = 12 - ( scos + 0.05d0) * 10.d0
2630 i2 = i1 + 1
2631 i1 = min(i1,11)
2632 i2 = min(i2,11)
2633 x1 = cos ( s(I1) * MPC_RADIANS_PER_DEGREE_R8 )
2634 x2 = cos ( s(I2) * MPC_RADIANS_PER_DEGREE_R8 )
2635 g1 = drcld(i1)
2636 g2 = drcld(i2)
2637 if (i1 == i2) then
2638 delta =g1
2639 else
2640 call lineq ( x1, x2, g1, g2, a, b, ierr )
2641 delta = a * scos + b
2642 end if
2643
2644 end subroutine cor_albedo
2645
2646 !--------------------------------------------------------------------------
2647 ! drcld
2648 !--------------------------------------------------------------------------
2649 real(8) function drcld(iz)
2650 !
2651 !:Purpose: Generaliser pour toutes les plateformes satellitaires.
2652 ! Ce sous-programme calcule la normalisation due
2653 ! a l'angle zenith solaire selon
2654 ! MINNIS-HARRISSON (COURBE FIG 7), P1038,JCAM 84.
2655 !
2656 !:Output: facteur de normalisation
2657 !
2658 implicit none
2659
2660 ! Arguments:
2661 integer, intent(in) :: iz ! Index for Sun angle bin
2662
2663 ! Locals:
2664 real(8),parameter :: drf(11)=(/1.000d0, 1.002d0, 1.042d0, 1.092d0, 1.178d0, 1.286d0, &
2665 1.420d0, 1.546d0, 1.710d0, 1.870d0, 2.050d0/)
2666
2667 drcld = drf (iz)
2668
2669 end function drcld
2670
2671
2672 !--------------------------------------------------------------------------
2673 ! visocn
2674 !--------------------------------------------------------------------------
2675 subroutine visocn(sz, satz, rz, anisot, zlamb, zcloud, ierr)
2676 !
2677 !:Purpose: This routine provides the corrective factors for the anisotropy
2678 ! of reflectance over clear ocean.
2679 !
2680 !
2681 !:Notes: Obtained from dr pat minnis,langley , and based on the work
2682 ! of minnis and harrisson,jcam 1984,p993.
2683 ! the routine is a look up table along with interpolation on the
2684 ! three angles.
2685 !
2686 implicit none
2687
2688 ! Arguments:
2689 real(8), intent(in) :: sz ! sun zenith angle in degrees (0 to 90)
2690 real(8), intent(in) :: satz ! satellite zenith angle (0 to 90)
2691 real(8), intent(in) :: rz ! relative angle in degrees (0-180) with 0 as backscattering and 180 as forward scattering
2692 real(8), intent(out) :: anisot ! anisotropic corrective factor (khi in minnis-harrisson)
2693 real(8), intent(out) :: zlamb ! corrective factor for lambertian reflectance (Ocean surface)
2694 real(8), intent(out) :: zcloud ! Same as zlamb but for cloud surface
2695 integer, intent(out) :: ierr ! Error code (0=ok; -1=problem with interpolation)
2696
2697 ! Locals:
2698 integer i1, i2, j1, j2, k1, k2, l, i, n, m, j, k
2699 real(8) cc, d1, d2, slope, intercept, x1, x2
2700 real(8) g1, g2, da(2), dd(2)
2701 real(8), parameter :: s(11)=(/0.0d0,18.19d0,31.79d0,41.41d0,49.46d0,56.63d0, &
2702 63.26d0,69.51d0,75.52d0,81.37d0,87.13d0/)
2703 real(8), parameter :: r(13)=(/0.0d0, 15.0d0, 30.0d0, 45.0d0, 60.0d0, 75.0d0, 90.0d0, &
2704 105.0d0, 120.0d0, 135.0d0, 150.0d0, 165.0d0, 180.0d0/)
2705 real(8), parameter :: v(10)=(/0.0d0, 10.0d0, 20.0d0, 30.0d0, 40.0d0, 50.0d0, 60.0d0, &
2706 70.0d0, 80.0d0, 90.0d0/)
2707 real(8) vnorm(11,10,13)
2708
2709 data ((vnorm(1,j,k),j=1,10),k=1,13)/ &
2710 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2711 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2712 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2713 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2714 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2715 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2716 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2717 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2718 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2719 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2720 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2721 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0, &
2722 2.668d0,2.210d0,1.105d0,0.979d0,0.810d0,0.735d0,0.785d0,0.979d0,1.092d0,1.174d0/
2723
2724 data ((vnorm(2,j,k),j=1,10),k=1,13)/ &
2725 1.154d0, .960d0, .896d0, .818d0, .748d0, .825d0, .922d0,1.018d0,1.179d0,1.334d0, &
2726 1.154d0, .954d0, .838d0, .799d0, .735d0, .786d0, .883d0, .960d0,1.128d0,1.250d0, &
2727 1.514d0, .973d0, .825d0, .786d0, .722d0, .754d0,0.838d0,0.922d0,1.063d0,1.160d0, &
2728 1.514d0,0.967d0,0.864d0,0.818d0,0.715d0,0.728d0,0.793d0,0.876d0,1.005d0,1.102d0, &
2729 1.514d0,0.967d0,0.896d0,0.889d0,0.702d0,0.696d0,0.773d0,0.851d0,0.954d0,1.038d0, &
2730 1.514d0,1.070d0,0.986d0,0.922d0,0.677d0,0.696d0,0.754d0,0.838d0,0.922d0,1.012d0, &
2731 1.514d0,1.270d0,0.967d0,0.870d0,0.677d0,0.664d0,0.709d0,0.773d0,0.857d0,0.954d0, &
2732 1.514d0,1.495d0,1.166d0,0.960d0,0.683d0,0.690d0,0.728d0,0.806d0,0.896d0,0.999d0, &
2733 1.514d0,1.959d0,1.534d0,1.025d0,0.973d0,0.709d0,0.754d0,0.857d0,0.954d0,1.050d0, &
2734 1.514d0,2.165d0,2.165d0,1.270d0,1.038d0,0.760d0,0.812d0,0.902d0,1.012d0,1.115d0, &
2735 1.514d0,2.275d0,2.262d0,1.688d0,1.115d0,0.780d0,0.857d0,0.954d0,1.070d0,1.173d0, &
2736 1.514d0,2.326d0,2.520d0,2.172d0,1.257d0,0.812d0,0.883d0,1.005d0,1.108d0,1.212d0, &
2737 1.514d0,2.359d0,2.951d0,2.255d0,1.411d0,0.980d0,0.915d0,1.050d0,1.160d0,1.295d0/
2738
2739 data ((vnorm(3,j,k),j=1,10),k=1,13)/ &
2740 0.897d0,0.792d0,0.765d0,0.765d0,0.778d0,0.897d0,0.996d0,1.095d0,1.306d0,1.431d0, &
2741 0.897d0,0.712d0,0.739d0,0.745d0,0.765d0,0.891d0,0.970d0,1.069d0,1.214d0,1.359d0, &
2742 0.897d0,0.666d0,0.699d0,0.745d0,0.759d0,0.811d0,0.917d0,1.042d0,1.148d0,1.306d0, &
2743 0.897d0,0.646d0,0.693d0,0.739d0,0.693d0,0.752d0,0.858d0,0.989d0,1.102d0,1.234d0, &
2744 0.897d0,0.686d0,0.679d0,0.726d0,0.679d0,0.693d0,0.792d0,0.924d0,1.049d0,1.154d0, &
2745 0.897d0,0.660d0,0.673d0,0.693d0,0.646d0,0.660d0,0.759d0,0.858d0,1.003d0,1.102d0, &
2746 0.897d0,0.673d0,0.765d0,0.792d0,0.712d0,0.600d0,0.699d0,0.811d0,0.963d0,1.055d0, &
2747 0.897d0,0.706d0,0.772d0,0.917d0,0.904d0,0.613d0,0.726d0,0.858d0,1.055d0,1.121d0, &
2748 0.897d0,0.825d0,0.924d0,0.996d0,0.989d0,0.686d0,0.778d0,0.937d0,1.115d0,1.181d0, &
2749 0.897d0,1.036d0,1.253d0,1.286d0,1.260d0,0.778d0,0.858d0,0.996d0,1.181d0,1.260d0, &
2750 0.897d0,1.201d0,1.788d0,1.986d0,1.827d0,0.884d0,0.851d0,1.062d0,1.227d0,1.333d0, &
2751 0.897d0,1.530d0,2.249d0,2.546d0,2.381d0,1.352d0,0.891d0,1.108d0,1.286d0,1.405d0, &
2752 0.897d0,1.854d0,2.401d0,3.325d0,2.559d0,1.590d0,0.937d0,1.168d0,1.214d0,1.425d0/
2753
2754 data ((vnorm(4,j,k),j=1,10),k=1,13)/ &
2755 0.752d0,0.800d0,0.745d0,0.717d0,0.759d0,0.891d0,1.149d0,1.309d0,1.469d0,1.650d0, &
2756 0.752d0,0.773d0,0.717d0,0.703d0,0.752d0,0.835d0,1.065d0,1.246d0,1.406d0,1.552d0, &
2757 0.752d0,0.731d0,0.689d0,0.703d0,0.745d0,0.814d0,0.988d0,1.176d0,1.323d0,1.476d0, &
2758 0.752d0,0.689d0,0.675d0,0.654d0,0.696d0,0.752d0,0.940d0,1.100d0,1.246d0,1.378d0, &
2759 0.752d0,0.675d0,0.661d0,0.633d0,0.668d0,0.717d0,0.877d0,1.030d0,1.176d0,1.309d0, &
2760 0.752d0,0.647d0,0.640d0,0.620d0,0.613d0,0.682d0,0.814d0,0.947d0,1.107d0,1.232d0, &
2761 0.752d0,0.633d0,0.620d0,0.613d0,0.606d0,0.640d0,0.773d0,0.898d0,1.044d0,1.162d0, &
2762 0.752d0,0.626d0,0.626d0,0.626d0,0.620d0,0.654d0,0.821d0,0.947d0,1.128d0,1.225d0, &
2763 0.752d0,0.633d0,0.633d0,0.633d0,0.647d0,0.675d0,0.877d0,1.009d0,1.183d0,1.274d0, &
2764 0.752d0,0.682d0,0.717d0,0.961d0,1.023d0,0.968d0,0.940d0,1.142d0,1.274d0,1.413d0, &
2765 0.752d0,0.856d0,1.037d0,1.434d0,1.594d0,1.441d0,1.044d0,1.225d0,1.323d0,1.545d0, &
2766 0.752d0,1.044d0,1.295d0,2.207d0,1.610d0,2.311d0,1.385d0,1.274d0,1.441d0,1.636d0, &
2767 0.752d0,1.079d0,1.524d0,2.541d0,3.564d0,3.014d0,1.942d0,1.462d0,1.552d0,1.726d0/
2768
2769 data ((vnorm(5,j,k),j=1,10),k=1,13)/ &
2770 0.552d0,0.588d0,0.617d0,0.638d0,0.724d0,0.860d0,1.133d0,1.362d0,1.556d0,1.678d0, &
2771 0.552d0,0.581d0,0.602d0,0.617d0,0.652d0,0.803d0,1.075d0,1.326d0,1.484d0,1.592d0, &
2772 0.552d0,0.559d0,0.588d0,0.595d0,0.617d0,0.731d0,1.018d0,1.283d0,1.412d0,1.527d0, &
2773 0.552d0,0.531d0,0.538d0,0.574d0,0.595d0,0.710d0,0.946d0,1.240d0,1.341d0,1.463d0, &
2774 0.552d0,0.516d0,0.523d0,0.552d0,0.559d0,0.695d0,0.911d0,1.226d0,1.291d0,1.412d0, &
2775 0.552d0,0.516d0,0.523d0,0.538d0,0.538d0,0.652d0,0.882d0,1.154d0,1.240d0,1.348d0, &
2776 0.552d0,0.516d0,0.523d0,0.538d0,0.523d0,0.595d0,0.774d0,1.075d0,1.169d0,1.269d0, &
2777 0.552d0,0.531d0,0.545d0,0.552d0,0.566d0,0.609d0,0.817d0,1.140d0,1.248d0,1.369d0, &
2778 0.552d0,0.538d0,0.545d0,0.566d0,0.581d0,0.645d0,0.911d0,1.240d0,1.319d0,1.441d0, &
2779 0.552d0,0.566d0,0.552d0,0.574d0,0.710d0,0.839d0,0.982d0,1.298d0,1.391d0,2.323d0, &
2780 0.552d0,0.566d0,0.559d0,0.710d0,1.147d0,1.176d0,1.040d0,1.348d0,1.671d0,2.674d0, &
2781 0.552d0,0.588d0,1.133d0,1.355d0,2.194d0,2.803d0,2.201d0,2.459d0,2.904d0,3.126d0, &
2782 0.552d0,0.710d0,1.341d0,1.757d0,3.026d0,3.900d0,4.445d0,4.503d0,4.445d0,4.503d0/
2783
2784 data ((vnorm(6,j,k),j=1,10),k=1,13)/ &
2785 0.551d0,0.627d0,0.665d0,0.734d0,0.826d0,0.971d0,1.231d0,1.537d0,1.721d0,1.866d0, &
2786 0.551d0,0.604d0,0.619d0,0.665d0,0.765d0,0.895d0,1.185d0,1.476d0,1.568d0,1.652d0, &
2787 0.551d0,0.597d0,0.604d0,0.619d0,0.734d0,0.849d0,1.101d0,1.346d0,1.453d0,1.568d0, &
2788 0.551d0,0.581d0,0.589d0,0.597d0,0.665d0,0.795d0,1.032d0,1.262d0,1.346d0,1.445d0, &
2789 0.551d0,0.558d0,0.558d0,0.566d0,0.612d0,0.727d0,0.987d0,1.201d0,1.262d0,1.399d0, &
2790 0.551d0,0.505d0,0.505d0,0.512d0,0.566d0,0.696d0,0.925d0,1.117d0,1.185d0,1.308d0, &
2791 0.551d0,0.474d0,0.497d0,0.512d0,0.535d0,0.673d0,0.864d0,1.048d0,1.124d0,1.216d0, &
2792 0.551d0,0.497d0,0.505d0,0.520d0,0.551d0,0.681d0,0.902d0,1.124d0,1.201d0,1.323d0, &
2793 0.551d0,0.535d0,0.535d0,0.551d0,0.566d0,0.711d0,1.017d0,1.201d0,1.269d0,1.422d0, &
2794 0.551d0,0.535d0,0.543d0,0.558d0,0.704d0,1.193d0,1.247d0,1.285d0,1.346d0,1.950d0, &
2795 0.551d0,0.543d0,0.551d0,0.581d0,0.994d0,1.545d0,1.583d0,1.354d0,2.019d0,2.883d0, &
2796 0.551d0,0.566d0,0.612d0,0.788d0,1.468d0,2.233d0,2.340d0,2.531d0,2.983d0,3.365d0, &
2797 0.551d0,0.658d0,0.665d0,1.101d0,2.134d0,3.120d0,4.221d0,4.856d0,4.956d0,5.613d0/
2798
2799 data ((vnorm(7,j,k),j=1,10),k=1,13)/ &
2800 0.545d0,0.606d0,0.683d0,0.744d0,0.798d0,0.990d0,1.228d0,1.704d0,1.850d0,2.049d0, &
2801 0.545d0,0.576d0,0.583d0,0.714d0,0.783d0,0.952d0,1.144d0,1.573d0,1.758d0,1.888d0, &
2802 0.545d0,0.560d0,0.568d0,0.629d0,0.744d0,0.875d0,1.105d0,1.504d0,1.642d0,1.788d0, &
2803 0.545d0,0.553d0,0.560d0,0.599d0,0.629d0,0.791d0,1.028d0,1.420d0,1.527d0,1.696d0, &
2804 0.545d0,0.545d0,0.553d0,0.599d0,0.606d0,0.714d0,0.990d0,1.335d0,1.451d0,1.581d0, &
2805 0.545d0,0.530d0,0.537d0,0.568d0,0.583d0,0.683d0,0.890d0,1.243d0,1.351d0,1.489d0, &
2806 0.545d0,0.491d0,0.499d0,0.507d0,0.576d0,0.622d0,0.791d0,1.182d0,1.282d0,1.389d0, &
2807 0.545d0,0.507d0,0.514d0,0.507d0,0.576d0,0.675d0,0.890d0,1.197d0,1.328d0,1.451d0, &
2808 0.545d0,0.522d0,0.537d0,0.522d0,0.591d0,0.760d0,0.944d0,1.259d0,1.389d0,1.527d0, &
2809 0.545d0,0.537d0,0.545d0,0.553d0,0.614d0,0.906d0,1.028d0,1.389d0,1.504d0,2.533d0, &
2810 0.545d0,0.553d0,0.553d0,0.576d0,0.637d0,1.036d0,1.550d0,1.658d0,1.934d0,3.277d0, &
2811 0.545d0,0.560d0,0.568d0,0.606d0,1.174d0,1.781d0,2.563d0,3.170d0,3.791d0,4.966d0, &
2812 0.545d0,0.591d0,0.614d0,1.259d0,2.065d0,2.824d0,3.761d0,4.498d0,5.902d0,6.148d0/
2813
2814 data ((vnorm(8,j,k),j=1,10),k=1,13)/ &
2815 0.514d0,0.539d0,0.596d0,0.694d0,0.832d0,1.004d0,1.444d0,1.869d0,2.203d0,2.538d0, &
2816 0.514d0,0.539d0,0.571d0,0.645d0,0.751d0,0.906d0,1.387d0,1.779d0,2.056d0,2.317d0, &
2817 0.514d0,0.547d0,0.555d0,0.612d0,0.702d0,0.824d0,1.281d0,1.681d0,1.934d0,2.203d0, &
2818 0.514d0,0.539d0,0.555d0,0.588d0,0.653d0,0.743d0,1.028d0,1.404d0,1.624d0,2.024d0, &
2819 0.514d0,0.539d0,0.547d0,0.555d0,0.588d0,0.710d0,0.889d0,1.191d0,1.420d0,1.820d0, &
2820 0.514d0,0.522d0,0.522d0,0.539d0,0.563d0,0.710d0,0.849d0,1.044d0,1.208d0,1.534d0, &
2821 0.514d0,0.481d0,0.506d0,0.514d0,0.539d0,0.694d0,0.824d0,1.028d0,1.200d0,1.371d0, &
2822 0.514d0,0.481d0,0.514d0,0.547d0,0.563d0,0.702d0,0.898d0,1.134d0,1.297d0,1.501d0, &
2823 0.514d0,0.490d0,0.514d0,0.555d0,0.588d0,0.726d0,0.955d0,1.265d0,1.379d0,1.648d0, &
2824 0.514d0,0.547d0,0.547d0,0.571d0,0.604d0,0.767d0,1.036d0,1.355d0,1.550d0,3.142d0, &
2825 0.514d0,0.563d0,0.579d0,0.604d0,0.612d0,0.832d0,1.909d0,2.848d0,3.917d0,4.790d0, &
2826 0.514d0,0.522d0,0.563d0,0.677d0,0.767d0,1.420d0,2.040d0,3.158d0,4.863d0,6.291d0, &
2827 0.514d0,0.588d0,0.588d0,0.612d0,0.824d0,2.032d0,3.109d0,4.969d0,6.846d0,7.695d0/
2828
2829 data ((vnorm(9,j,k),j=1,10),k=1,13)/ &
2830 0.572d0,0.608d0,0.679d0,0.751d0,0.831d0,1.001d0,1.377d0,1.913d0,2.512d0,2.879d0, &
2831 0.572d0,0.572d0,0.608d0,0.679d0,0.760d0,0.930d0,1.243d0,1.707d0,2.369d0,2.700d0, &
2832 0.572d0,0.563d0,0.590d0,0.644d0,0.706d0,0.831d0,1.171d0,1.618d0,2.190d0,2.378d0, &
2833 0.572d0,0.554d0,0.563d0,0.599d0,0.662d0,0.760d0,1.010d0,1.502d0,2.011d0,2.235d0, &
2834 0.572d0,0.545d0,0.563d0,0.590d0,0.626d0,0.715d0,0.885d0,1.323d0,1.815d0,2.119d0, &
2835 0.572d0,0.527d0,0.554d0,0.572d0,0.608d0,0.670d0,0.724d0,1.144d0,1.618d0,1.868d0, &
2836 0.572d0,0.545d0,0.572d0,0.572d0,0.599d0,0.662d0,0.724d0,1.117d0,1.484d0,1.761d0, &
2837 0.572d0,0.554d0,0.590d0,0.599d0,0.608d0,0.679d0,0.760d0,1.216d0,1.582d0,1.922d0, &
2838 0.572d0,0.572d0,0.599d0,0.608d0,0.635d0,0.715d0,0.822d0,1.377d0,1.707d0,2.056d0, &
2839 0.572d0,0.590d0,0.608d0,0.635d0,0.662d0,0.742d0,0.912d0,1.529d0,3.075d0,4.693d0, &
2840 0.572d0,0.590d0,0.626d0,0.644d0,0.670d0,0.760d0,1.109d0,1.564d0,3.111d0,4.702d0, &
2841 0.572d0,0.599d0,0.644d0,0.662d0,0.688d0,0.822d0,1.788d0,2.816d0,5.346d0,7.295d0, &
2842 0.572d0,0.608d0,0.662d0,0.670d0,0.715d0,1.851d0,3.227d0,4.810d0,6.669d0,9.557d0/
2843
2844 data ((vnorm(10,j,k),j=1,10),k=1,13)/ &
2845 0.552d0,0.606d0,0.639d0,0.671d0,0.704d0,0.899d0,1.223d0,2.479d0,3.194d0,3.573d0, &
2846 0.552d0,0.574d0,0.606d0,0.628d0,0.682d0,0.855d0,1.148d0,2.339d0,2.642d0,3.378d0, &
2847 0.552d0,0.563d0,0.552d0,0.595d0,0.639d0,0.834d0,1.061d0,2.014d0,2.404d0,2.891d0, &
2848 0.552d0,0.563d0,0.509d0,0.552d0,0.628d0,0.801d0,0.985d0,1.689d0,2.176d0,2.653d0, &
2849 0.552d0,0.574d0,0.509d0,0.520d0,0.585d0,0.747d0,0.888d0,1.332d0,1.970d0,2.458d0, &
2850 0.552d0,0.531d0,0.509d0,0.509d0,0.531d0,0.682d0,0.801d0,1.191d0,1.819d0,2.425d0, &
2851 0.552d0,0.498d0,0.498d0,0.498d0,0.520d0,0.639d0,0.747d0,1.126d0,1.711d0,2.317d0, &
2852 0.552d0,0.498d0,0.509d0,0.509d0,0.541d0,0.671d0,0.780d0,1.278d0,1.862d0,2.598d0, &
2853 0.552d0,0.498d0,0.509d0,0.520d0,0.574d0,0.693d0,0.812d0,1.602d0,2.035d0,2.793d0, &
2854 0.552d0,0.520d0,0.520d0,0.531d0,0.595d0,0.725d0,0.844d0,1.916d0,2.588d0,3.768d0, &
2855 0.552d0,0.531d0,0.541d0,0.574d0,0.628d0,0.780d0,1.039d0,2.349d0,3.313d0,5.652d0, &
2856 0.552d0,0.574d0,0.563d0,0.606d0,0.660d0,0.812d0,1.797d0,3.010d0,5.478d0,7.492d0, &
2857 0.552d0,0.650d0,0.671d0,0.704d0,0.801d0,1.029d0,2.436d0,3.465d0,7.828d0,10.578d0/
2858
2859 data ((vnorm(11,j,k),j=1,10),k=1,13)/ &
2860 0.518d0,0.576d0,0.605d0,0.633d0,0.662d0,0.864d0,1.238d0,2.620d0,3.455d0,3.887d0, &
2861 0.518d0,0.547d0,0.576d0,0.576d0,0.633d0,0.835d0,1.123d0,2.447d0,2.821d0,3.656d0, &
2862 0.518d0,0.518d0,0.518d0,0.547d0,0.605d0,0.806d0,1.036d0,2.102d0,2.533d0,3.080d0, &
2863 0.518d0,0.518d0,0.461d0,0.518d0,0.576d0,0.777d0,0.950d0,1.727d0,2.274d0,2.821d0, &
2864 0.518d0,0.547d0,0.461d0,0.489d0,0.547d0,0.720d0,0.864d0,1.353d0,2.044d0,2.591d0, &
2865 0.518d0,0.489d0,0.461d0,0.461d0,0.489d0,0.662d0,0.777d0,1.180d0,1.871d0,2.562d0, &
2866 0.518d0,0.461d0,0.461d0,0.461d0,0.489d0,0.605d0,0.720d0,1.123d0,1.756d0,2.418d0, &
2867 0.518d0,0.461d0,0.461d0,0.461d0,0.518d0,0.633d0,0.749d0,1.296d0,1.929d0,2.764d0, &
2868 0.518d0,0.461d0,0.461d0,0.489d0,0.547d0,0.662d0,0.777d0,1.641d0,2.130d0,2.994d0, &
2869 0.518d0,0.489d0,0.489d0,0.489d0,0.547d0,0.691d0,0.806d0,1.986d0,2.735d0,4.117d0, &
2870 0.518d0,0.489d0,0.489d0,0.547d0,0.576d0,0.749d0,1.008d0,2.476d0,3.599d0,6.334d0, &
2871 0.518d0,0.547d0,0.518d0,0.576d0,0.633d0,0.777d0,1.842d0,3.224d0,6.132d0,8.550d0, &
2872 0.518d0,0.605d0,0.633d0,0.662d0,0.777d0,1.008d0,2.562d0,3.771d0,8.953d0,12.293d0/
2873
2874 ! compute sun zenith bin
2875 cc = cos( sz * MPC_RADIANS_PER_DEGREE_R8)
2876 i1 = 12.d0 - (cc + 0.05d0) * 10.d0
2877 i2 = i1 + 1
2878 if (i1 >= 11) i1 = 11
2879 if (i1 == 11) i2 = i1
2880
2881 ! compute sat zenith bin
2882 j1 = int(satz / 10.d0) + 1
2883 j2 = j1 + 1
2884 if (j1 == 10) j2 = j1
2885
2886 ! compute relative azimuth bin
2887 k1 = RZ / 15.d0 + 1.d0
2888 k2 = k1 + 1
2889 if (k1 == 13) k2 = k1
2890
2891 ! interpolate
2892 ierr = 0
2893 do l=i1,i2
2894 i = l -i1 + 1
2895
2896 ! between r's for constant s
2897 do n=k1,k2
2898
2899 ! between v's for constant r and s
2900 m = n - k1 + 1
2901 d1 = vnorm(l,j1,n)
2902 d2 = vnorm(l,j2,n)
2903 if (d1 == d2) then
2904 da(m) = d1
2905 else
2906 call lineq(V(j1),V(j2),d1,d2,slope,intercept,ierr)
2907 da(m) = slope * satz + intercept
2908 end if
2909 end do
2910 if(k1 == k2) then
2911 dd(i) = da(1)
2912 else
2913 call lineq(R(k1),R(k2),da(1),da(2),slope,intercept,ierr)
2914 dd(i) = slope * RZ + intercept
2915 end if
2916 end do
2917
2918 ! between s's using result of other interpolations
2919 if(i1 == i2) then
2920 zlamb = drm(i1)
2921 zcloud = drcld(i1)
2922 anisot = dd(1)
2923 else
2924 x1 = cos(s(i1) * MPC_RADIANS_PER_DEGREE_R8)
2925 x2 = cos(s(i2) * MPC_RADIANS_PER_DEGREE_R8)
2926 call lineq(x1,x2,dd(1),dd(2),slope,intercept,ierr)
2927 anisot = slope * cc + intercept
2928 g1 = drm(i1)
2929 g2 = drm(i2)
2930 call lineq(x1,x2,g1,g2,slope,intercept,ierr)
2931 zlamb = slope * cc + intercept
2932 g1 = drcld(i1)
2933 g2 = drcld(i2)
2934 call lineq(x1,x2,g1,g2,slope,intercept,ierr)
2935 zcloud = slope * cc + intercept
2936 end if
2937
2938 if (anisot < 0.) then
2939 ierr = -1
2940 anisot = 1.d0
2941 zlamb = drm(i1)
2942 zcloud = drcld(i1)
2943 end if
2944
2945 end subroutine visocn
2946
2947 !--------------------------------------------------------------------------
2948 ! lineq
2949 !--------------------------------------------------------------------------
2950 subroutine lineq(x1, x2, y1, y2, a, b, ierr)
2951 !
2952 !:Purpose: calculate slope and intercept of a line.
2953 !
2954 implicit none
2955
2956 ! Arguments:
2957 real(8), intent(in) :: x1 ! coordinate x of point 1
2958 real(8), intent(in) :: x2 ! coordinate x of point 2
2959 real(8), intent(in) :: y1 ! coordinate y of point 1
2960 real(8), intent(in) :: y2 ! coordinate y of point 2
2961 real(8), intent(out) :: a ! slope
2962 real(8), intent(out) :: b ! intercept
2963 integer, intent(out) :: ierr ! error code (0=ok)
2964
2965 ierr = 0
2966
2967 if ( (x2 - x1) == 0.d0) then
2968 ierr = -1
2969 return
2970 end if
2971
2972 a = ( y2 - y1) / (x2 - x1)
2973 b = y1 - a * x1
2974
2975 end subroutine lineq
2976
2977
2978 !--------------------------------------------------------------------------
2979 ! drm
2980 !--------------------------------------------------------------------------
2981 real(8) function drm(iz)
2982 !
2983 !:Purpose: Normalization for sun zenith angle (lambertian)
2984 ! for ocean.
2985 !
2986 !:Outputs: normalization factor
2987 !
2988 implicit none
2989
2990 ! Arguments:
2991 integer, intent(in) :: iz ! index
2992
2993 ! Locals:
2994 real(8),parameter :: drf(11)=(/1.d0,1.0255d0,1.1197d0,1.2026d0,1.3472d0, &
2995 1.4926d0,1.8180d0,2.1980d0, 2.8180d0,3.8615d0,4.3555d0/)
2996
2997 drm = drf(IZ)
2998
2999 end function drm
3000
3001
3002end module multiIRbgck_mod