1module biasCorrectionSat_mod
2 ! MODULE biasCorrectionSat_mod (prefix='bcs' category='1. High-level functionality')
3 !
4 !:Purpose: Performs the bias correction for satellite radiance
5 ! data. This includes both the traditional approach based
6 ! on regression and the variational bias correction approach
7 ! for estimating the bias. Existing bias correction estimates
8 ! can also be applied to observations.
9 !
10 use utilities_mod
11 use ramDisk_mod
12 use MathPhysConstants_mod
13 use obsSpaceData_mod
14 use controlVector_mod
15 use midasMpi_mod
16 use rttov_const, only : ninst
17 use tovsNL_mod
18 use timeCoord_mod
19 use columnData_mod
20 use codePrecision_mod
21 use localizationFunction_mod
22 use HorizontalCoord_mod
23 use verticalCoord_mod
24 use gridStateVector_mod
25 use gridStateVectorFileIO_mod
26 use stateToColumn_mod
27 use codtyp_mod
28 use timeCoord_mod
29 use clibInterfaces_mod
30 use obserrors_mod
31 use fSQLite
32 use obsfiles_mod
33
34 implicit none
35 save
36 private
37
38 public :: bcs_setup, bcs_calcBias_tl, bcs_calcBias_ad, bcs_writeBias, bcs_finalize
39 public :: bcs_removeBiasCorrection, bcs_refreshBiasCorrection
40 public :: bcs_do_regression, bcs_filterObs, bcs_computeResidualsStatistics, bcs_calcBias
41 public :: bcs_removeOutliers, bcs_applyBiasCorrection
42 public :: bcs_mimicSatbcor
43 public :: bcs_readConfig
44 public :: bcs_dumpBiasToSqliteAfterThinning
45
46 type :: struct_chaninfo
47 integer :: numActivePredictors
48 logical :: isDynamic
49 integer :: channelNum
50 character(len=1) :: bcmode
51 character(len=1) :: bctype
52 integer, allocatable :: predictorIndex(:)
53 real(8), allocatable :: coeff(:)
54 real(8), allocatable :: coeffIncr(:)
55 real(8), allocatable :: coeff_fov(:)
56 real(8), allocatable :: coeff_offset(:)
57 integer :: coeff_nobs
58 real(8), allocatable :: coeffIncr_fov(:)
59 real(8), allocatable :: stddev(:)
60 real(8), allocatable :: coeffCov(:,:)
61 end type struct_chaninfo
62
63 type :: struct_bias
64 type(struct_chaninfo), allocatable :: chans(:)
65 integer :: numscan
66 integer :: numChannels
67 real(8), allocatable :: BHalfScanBias(:,:)
68 real(8), allocatable :: BMinusHalfScanBias(:,:)
69 end type struct_bias
70
71 type(struct_bias), allocatable :: bias(:)
72 type(struct_vco), pointer :: vco_mask => null()
73 type(struct_hco), pointer :: hco_mask => null()
74 type(struct_columnData) :: column_mask
75 logical :: initialized = .false.
76 logical :: bcs_mimicSatbcor
77 logical :: doRegression
78 integer, parameter :: NumPredictors = 7
79 integer, parameter :: NumPredictorsBcif = 6
80 integer, parameter :: maxfov = 120
81 integer, parameter :: maxNumInst = 25
82 integer, parameter :: maxPassiveChannels = 15
83
84 real(8), allocatable :: trialHeight300m1000(:)
85 real(8), allocatable :: trialHeight50m200(:)
86 real(8), allocatable :: trialHeight1m10(:)
87 real(8), allocatable :: trialHeight5m50(:)
88 real(8), allocatable :: RadiosondeWeight(:)
89 real(8), allocatable :: trialTG(:)
90 integer :: nobs
91 integer, external :: fnom, fclos
92 character(len=2), parameter :: predTab(0:7) = [ "SB", "KK","T1", "T2", "T3", "T4", "SV", "TG"]
93 integer :: passiveChannelNumber(maxNumInst)
94 ! Namelist variables
95 character(len=5) :: biasMode ! "varbc" for varbc, "reg" to compute bias correction coefficients by regression, "apply" to compute and apply bias correction
96 logical :: biasActive ! logical variable to activate the module
97 logical :: outstats ! flag to activate output of residual statistics in "reg" mode
98 logical :: mimicSatbcor ! in "reg" mode compute regression coefficients the same way as the original satbcor program
99 logical :: weightedestimate ! flag to activate radiosonde weighting for bias correction computation in "reg" mode
100 logical :: filterObs ! flag to activate additional observation filtering in "reg" mode. If it is .false. only observations selected for assimilation will be used in the linear regression
101 logical :: removeBiasCorrection ! flag to activate removal of an already present bias correction
102 logical :: refreshBiasCorrection !flag to replace an existing bias correction with a new one
103 logical :: centerPredictors ! flag to transparently remove predictor mean in "reg" mode (more stable problem; very little impact on the result)
104 logical :: outCoeffCov ! flag to activate output of coefficients error covariance (useful for EnKF system)
105 logical :: outOmFPredCov ! flag to activate output of O-F/predictors coefficients covariances and correlations
106 real(8) :: scanBiasCorLength ! if positive and .not. mimicSatBcor use error correlation between scan positions with the given correlation length
107 real(8) :: bg_stddev(NumPredictors) ! background error for predictors ("varbc" mode)
108 character(len=7) :: cinst(maxNumInst) ! to read the bcif file for each instrument in cinst
109 character(len=3) :: cglobal(maxNumInst) ! a "global" parameter and
110 integer :: nbscan(maxNumInst) ! the number of scan positions are necessary
111 integer :: passiveChannelList(maxNumInst, maxPassiveChannels)
112 ! To understand the meaning of the following parameters controling filtering,
113 ! please see https://wiki.cmc.ec.gc.ca/images/f/f6/Unified_SatRad_Dyn_bcor_v19.pdf pages 20-22
114 logical :: offlineMode ! flag to select offline mode for bias correction computation
115 logical :: allModeSsmis ! flag to select "ALL" mode for SSMIS
116 logical :: allModeTovs ! flag to select "ALL" mode for TOVS (AMSU-A, AMSU-B, MHS, ATMS, MWHS-2)
117 logical :: allModeCsr ! flag to select "ALL" mode for CSR (GOES, SEVIRI, MVIRI, ABI, etc..)
118 logical :: allModeHyperIr! flag to select "ALL" mode for hyperSpectral Infrared (AIRS, IASI, CrIS)
119 logical :: dumpToSqliteAfterThinning ! option to output all usefull parameters to sqlite files after thinning
120 namelist /nambiassat/ biasActive, biasMode, bg_stddev, removeBiasCorrection, refreshBiasCorrection
121 namelist /nambiassat/ centerPredictors, scanBiasCorLength, mimicSatbcor, weightedEstimate
122 namelist /nambiassat/ cglobal, cinst, nbscan, passiveChannelList, filterObs, outstats, outCoeffCov
123 namelist /nambiassat/ offlineMode, allModeSsmis, allModeTovs, allModeCsr, allModeHyperIr
124 namelist /nambiassat/ dumpToSqliteAfterThinning, outOmFPredCov
125contains
126
127 !-----------------------------------------------------------------------
128 ! bcs_readConfig
129 !-----------------------------------------------------------------------
130 subroutine bcs_readConfig()
131 !
132 !:Purpose: Read nambiassat namelist section
133 !
134 implicit none
135
136 ! Locals:
137 integer :: ierr, nulnam
138 logical, save :: firstCall = .true.
139 integer :: instrumentIndex, channelIndex
140
141 if (.not. firstCall) return
142 firstCall = .false.
143
144 ! set default values for namelist variables
145 biasActive = .false.
146 biasMode = "varbc"
147 bg_stddev(:) = 0.0d0
148 removeBiasCorrection = .false.
149 filterObs = .false.
150 refreshBiasCorrection = .false.
151 centerPredictors = .false.
152 mimicSatbcor = .true.
153 scanBiasCorLength = -1.d0
154 weightedEstimate = .false.
155 outCoeffCov = .false.
156 outOmFPredCov = .false.
157 nbscan(:) = -1
158 cinst(:) = "XXXXXXX"
159 cglobal(:) = "XXX"
160 outstats = .false.
161 offlineMode = .false.
162 allModeSsmis = .true.
163 allModeTovs = .true.
164 allModeCsr = .true.
165 allModeHyperIr = .false.
166 dumpToSqliteAfterThinning = .false.
167 passiveChannelNumber(:) = 0
168 passiveChannelList(:,:) = -1
169 !
170 ! read in the namelist NAMBIASSAT
171 if (utl_isNamelistPresent('nambiassat', './flnml')) then
172 nulnam = 0
173 ierr = fnom(nulnam, './flnml', 'FTN+SEQ+R/O', 0)
174 read(nulnam,nml=nambiassat,iostat=ierr)
175 if (ierr /= 0) call utl_abort('bcs_readConfig: Error reading namelist section nambiassat')
176 if (mmpi_myid == 0) write(*,nml=nambiassat)
177 ierr = fclos(nulnam)
178 else
179 write(*,*)
180 write(*,*) 'bcs_readconfig: nambiassat is missing in the namelist. The default value will be taken.'
181 end if
182
183 bcs_mimicSatbcor = mimicSatbcor
184 doRegression = (trim(biasMode) == "reg")
185
186 do instrumentIndex = 1, maxNumInst
187 do channelIndex = 1, maxPassiveChannels
188 if (passiveChannelList(instrumentIndex,channelIndex) > 0) then
189 passiveChannelNumber(instrumentIndex) = passiveChannelNumber(instrumentIndex) + 1
190 end if
191 end do
192 end do
193
194 end subroutine bcs_readConfig
195
196 !-----------------------------------------------------------------------
197 ! bcs_setup
198 !-----------------------------------------------------------------------
199 subroutine bcs_setup()
200 implicit none
201
202 ! Locals:
203 integer :: cvdim
204 integer :: iSensor, iPredictor, instIndex
205 integer :: iChan
206 integer :: iPred, jPred, kPred, iScan1, iScan2
207 character(len=85) :: bcifFile
208 character(len=10) :: instrName, instrNamecoeff, satNamecoeff
209 logical :: bcifExists
210 ! variables from background coeff file
211 integer :: nfov, exitCode
212 character(len=2) :: predBCIF(tvs_maxchannelnumber,numpredictorsBCIF)
213 integer :: canBCIF(tvs_maxchannelnumber), npredBCIF(tvs_maxchannelnumber), ncanBcif, npredictors
214 character(len=1) :: bcmodeBCIF(tvs_maxchannelnumber), bctypeBCIF(tvs_maxchannelnumber)
215 character(len=3) :: global
216 character(len=128) :: errorMessage
217 real(8), allocatable :: Bmatrix(:,:)
218
219 call bcs_readConfig()
220
221 cvdim = 0
222
223 if (biasActive) then
224
225 if (scanBiasCorLength > 0.d0) call lfn_Setup('FifthOrder')
226
227 allocate(bias(tvs_nSensors))
228
229 do iSensor = 1, tvs_nSensors
230
231 write(*,*) "bcs_setup: iSensor = ", iSensor
232
233 instrName = InstrNametoCoeffFileName(tvs_instrumentName(iSensor))
234 instrNamecoeff = InstrNameinCoeffFile(tvs_instrumentName(iSensor))
235 satNamecoeff = SatNameinCoeffFile(tvs_satelliteName(iSensor))
236
237 bcifFile = 'bcif_' // trim(instrName)
238
239 global = "XXX"
240 nfov = -1
241 do instIndex = 1, size(cinst)
242 if (trim(instrNamecoeff) == trim(cinst(instIndex))) then
243 global = cglobal(instIndex)
244 nfov = nbscan(instIndex)
245 end if
246 end do
247 if (nfov == -1) then
248 write(*,*) "bcs_setup: Problem with instrName ", instrNamecoeff
249 write(*,'(15(A10,1x))') cinst(:)
250 call utl_abort('bcs_setup: check nambiassat namelist')
251 end if
252
253 inquire(file=trim(bcifFile), exist=bcifExists)
254 if (bcifExists) then
255 !read bcif (Bias Correction Information File)
256 call read_bcif(bcifFile, tvs_isNameHyperSpectral(instrName), ncanBcif, &
257 canBCIF, bcmodeBCIF, bctypeBCIF, npredBCIF, predBCIF, global, exitcode)
258 if (exitcode /= 0) then
259 call utl_abort("bcs_setup: Problem in read_bcif while reading " // trim(bcifFile))
260 end if
261
262 bias(iSensor)%numChannels = ncanBcif
263
264 allocate(bias(iSensor)%chans(ncanBcif))
265
266 do ichan=1, ncanBcif
267 bias(iSensor) % chans(ichan) % channelNum = canBCIF(ichan + 1)
268 bias(iSensor) % chans(ichan) % coeff_nobs = 0
269 bias(iSensor) % chans(ichan) % bcmode = bcmodeBCIF(ichan + 1)
270 bias(iSensor) % chans(ichan) % bctype = bctypeBCIF(ichan + 1)
271 bias(iSensor) % chans(ichan) % isDynamic = ( (biasmode == "varbc" .and. bcmodeBCIF(ichan + 1) == "D") .or. biasmode /= "varbc")
272 npredictors = 1 + npredBCIF(ichan + 1)
273 bias(iSensor) % chans(ichan) % numActivePredictors = npredictors
274
275 allocate( bias(iSensor) % chans(ichan) % stddev( npredictors ) )
276 allocate( bias(iSensor) % chans(ichan) % coeffIncr( npredictors ) )
277 allocate( bias(iSensor) % chans(ichan) % coeff( npredictors ) )
278 allocate( bias(iSensor) % chans(ichan) % coeff_offset( npredictors ) )
279 allocate( bias(iSensor) % chans(ichan) % predictorIndex( npredictors ) )
280 bias(iSensor) % chans(ichan) % stddev(:) = 0.d0
281 bias(iSensor) % chans(ichan) % coeffIncr(:) = 0.d0
282 bias(iSensor) % chans(ichan) % coeff(:) = MPC_missingValue_R8
283 bias(iSensor) % chans(ichan) % coeff_offset(:) = 0.d0
284
285 bias(iSensor)%chans(ichan)% predictorIndex(1) = 1 !the constant term is always included
286 jPred = 1
287 do ipred = 1, npredBCIF(ichan + 1)
288 jPred = jPred + 1
289 select case(predBCIF(ichan + 1, ipred))
290 case('T1')
291 kpred = 2
292 case('T2')
293 kpred = 3
294 case('T3')
295 kpred = 4
296 case('T4')
297 kpred = 5
298 case('SV')
299 kpred = 6
300 case('TG')
301 kpred = 7
302 case default
303 write(errorMessage,*) "bcs_setup: Unknown predictor ", predBCIF(ichan+1, ipred), ichan, ipred
304 call utl_abort(errorMessage)
305 end select
306 bias(iSensor)%chans(ichan)%predictorIndex(jPred) = kpred
307 end do
308 end do
309 else
310 call utl_abort("bcs_setup: Error : " // trim(bcifFile) // " not present !")
311 end if
312
313 bias(iSensor)%numscan = nfov
314
315 allocate( bias(iSensor) % BHalfScanBias (nfov,nfov))
316 if (doRegression) allocate( bias(iSensor) % BMinusHalfScanBias (nfov,nfov))
317 allocate( Bmatrix(nfov,nfov))
318 do ichan=1, ncanBcif
319 allocate( bias(iSensor) % chans(ichan) % coeffIncr_fov(nfov))
320 allocate( bias(iSensor) % chans(ichan) % coeff_fov(nfov))
321 bias(iSensor) % chans(ichan) % coeffIncr_fov(:) = 0.d0
322 bias(iSensor) % chans(ichan) % coeff_fov(:) = MPC_missingValue_R8
323 end do
324
325 do ichan = 1, ncanBcif
326 if (bias(iSensor)%chans(ichan)%isDynamic) then
327 do iPredictor = 1, bias(iSensor)%chans(ichan)%numActivePredictors
328 bias(iSensor)%chans(ichan)%stddev(iPredictor) = bg_stddev(bias(iSensor)%chans(ichan)%PredictorIndex(iPredictor))
329 end do
330 end if
331 end do
332
333 if (trim(biasMode) == "varbc") then
334 !change dimension of control vector
335 do ichan = 1, ncanBcif
336 if (bias(iSensor)%chans(ichan)%isDynamic) &
337 cvdim = cvdim + bias(iSensor)%chans(ichan)%numActivePredictors - 1 + bias(iSensor)%numScan
338 end do
339 end if
340
341 if (allocated(Bmatrix)) then
342 if (scanBiasCorLength > 0.d0) then
343 do iScan2 = 1, nfov
344 do iScan1 = 1, nfov
345 Bmatrix(iScan1,iScan2) = bg_stddev(1) * bg_stddev(1) * lfn_Response(1.d0*abs(iScan1-iScan2), scanBiasCorLength)
346 end do
347 end do
348 else
349 Bmatrix(:,:) = 0.d0
350 do iScan1 = 1, nfov
351 Bmatrix(iScan1,iScan1) = bg_stddev(1) * bg_stddev(1)
352 end do
353 end if
354 bias(iSensor)%BHalfScanBias(:,:) = Bmatrix(:,:)
355 call utl_matsqrt(bias(iSensor)%BHalfScanBias, nfov, 1.d0, printInformation_opt=.true.)
356 if (doRegression) then
357 bias(iSensor)%BMinusHalfScanBias(:,:) = Bmatrix(:,:)
358 call utl_matsqrt(bias(iSensor)%BMinusHalfScanBias, nfov, -1.d0, printInformation_opt=.true.)
359 end if
360 deallocate(Bmatrix)
361 end if
362
363 end do
364
365 end if
366
367 if (trim(biasMode) == "varbc" .and. cvdim > 0) then
368 if (mmpi_myid > 0) cvdim = 0 ! for minimization, all coefficients only on task 0
369 call cvm_setupSubVector('BIAS', 'BIAS', cvdim)
370 end if
371
372 call bcs_readCoeffs() ! Read coefficient files in the case of bias correction application (biasMode=="apply")
373
374 end subroutine bcs_setup
375
376 !-----------------------------------------------------------------------
377 ! bcs_readCoeffs
378 !-----------------------------------------------------------------------
379 subroutine bcs_readCoeffs()
380 !
381 !:Purpose: Fill the bias structure with read static and dynamic bias correction coefficient files
382 !
383 implicit none
384
385 ! Locals:
386 integer :: iSensor, iSat, jchannel, jChan
387 integer :: satIndexDynamic, satIndexStatic
388 integer :: chanindexDynamic, chanindexStatic
389 character(len=10) :: instrName, instrNamecoeff, satNamecoeff
390 character(len=64) :: dynamicCoeffFile, staticCoeffFile
391 logical :: corrected
392 integer :: nfov, npredictors
393 character(len=10) :: satsDynamic(tvs_nsensors) ! satellite names
394 integer :: chansDynamic(tvs_nsensors,tvs_maxchannelnumber) ! channel numbers
395 real(8) :: fovbiasDynamic(tvs_nsensors,tvs_maxchannelnumber,maxfov)! bias as F(fov)
396 real(8) :: coeffDynamic(tvs_nsensors,tvs_maxchannelnumber,NumPredictors + 1)
397 integer :: nsatDynamic
398 integer :: nchanDynamic(tvs_nsensors) !number of channels
399 integer :: nfovDynamic
400 integer :: npredDynamic(tvs_nsensors,tvs_maxchannelnumber) !number of predictors
401 character(len=7) :: cinstrumDynamic ! string: instrument (e.g. AMSUB)
402 character(len=2) :: ptypesDynamic(tvs_nsensors,tvs_maxchannelnumber,NumPredictors)
403 integer :: ndataDynamic(tvs_nsensors,tvs_maxchannelnumber) !number of channels
404 character(len=10) :: satsStatic(tvs_nsensors) ! satellite names
405 integer :: chansStatic(tvs_nsensors,tvs_maxchannelnumber) !channel numbers
406 real(8) :: fovbiasStatic(tvs_nsensors,tvs_maxchannelnumber,maxfov)!bias as F(fov)
407 real(8) :: coeffStatic(tvs_nsensors, tvs_maxchannelnumber,NumPredictors + 1)
408 integer :: nsatStatic
409 integer :: nchanStatic(tvs_nsensors) !number of channels
410 integer :: nfovStatic
411 integer :: npredStatic(tvs_nsensors,tvs_maxchannelnumber) ! number of predictors
412 character(len=7) :: cinstrumStatic ! string: instrument (e.g. AMSUB) 9
413 character(len=2) :: ptypesStatic(tvs_nsensors,tvs_maxchannelnumber,NumPredictors)
414 integer :: ndataStatic(tvs_nsensors,tvs_maxchannelnumber) ! number of channels
415
416 if (biasActive .and. biasMode == "apply") then
417
418 ! 1 fichier de coefficient par intrument avec les differentes plateformes
419 ! Cas particulier GEORAD (CSR)
420
421 do iSensor = 1, tvs_nSensors
422
423 write(*,*) "bcs_readCoeffs: iSensor = ", iSensor
424
425 instrName = InstrNametoCoeffFileName(tvs_instrumentName(iSensor))
426 instrNamecoeff = InstrNameinCoeffFile(tvs_instrumentName(iSensor))
427 satNamecoeff = SatNameinCoeffFile(tvs_satelliteName(iSensor))
428
429 dynamicCoeffFile = "coeff_file_" // trim(instrName)
430 staticCoeffFile = "static_coeff_file_" // trim(instrName)
431
432 if ( tvs_isNameGeostationary(instrName)) then
433 dynamicCoeffFile = trim(dynamicCoeffFile) // "." // trim(satNamecoeff)
434 staticCoeffFile = trim(staticCoeffFile) // "." // trim(satNamecoeff)
435 end if
436
437 call read_coeff(satsDynamic, chansDynamic, fovbiasDynamic, coeffDynamic, nsatDynamic, nchanDynamic, nfovDynamic, &
438 npredDynamic, cinstrumDynamic, dynamicCoeffFile, ptypesDynamic, ndataDynamic)
439
440 call read_coeff(satsStatic, chansStatic, fovbiasStatic, coeffStatic, nsatStatic, nchanStatic, nfovStatic, &
441 npredStatic, cinstrumStatic, staticCoeffFile, ptypesStatic, ndataStatic)
442 write(*,*) "bcs_readCoeffs: cinstrumDynamic = ", cinstrumDynamic
443 write(*,*) "bcs_readCoeffs: cinstrumStatic = ", cinstrumStatic
444
445 satIndexDynamic = -1
446 do iSat = 1, nsatDynamic
447 if (trim(satNameCoeff) /= trim(satsDynamic(iSat)) .or. trim(instrNamecoeff) /= trim(cinstrumDynamic)) cycle
448 satIndexDynamic = iSat
449 end do
450
451 satIndexStatic = -1
452 do iSat = 1, nsatStatic
453 if (trim(satNameCoeff) /= trim(satsStatic(iSat)) .or. trim(instrNamecoeff) /= trim(cinstrumStatic)) cycle
454 satIndexStatic = iSat
455 end do
456
457 nfov = bias(iSensor)%numscan
458
459 do jChannel = 1, bias(iSensor)%numChannels
460
461 chanindexDynamic = -1
462 if (satIndexDynamic > 0) then
463 do jChan = 1, nchanDynamic(satIndexDynamic)
464 if (chansDynamic(satIndexDynamic,jChan) == bias(iSensor)%chans(jChannel)%channelNum) then
465 chanindexDynamic = jChan
466 exit
467 end if
468 end do
469 end if
470
471 chanindexStatic = -1
472 if (satIndexStatic > 0) then
473 do jChan = 1, nchanStatic(satIndexStatic)
474 if (chansStatic(satIndexStatic,jChan) == bias(iSensor)%chans(jChannel)%channelNum) then
475 chanindexStatic = jChan
476 exit
477 end if
478 end do
479 end if
480 npredictors = bias(iSensor)%chans(jChannel)%numActivePredictors
481
482 corrected = .true.
483 select case(bias(iSensor)%chans(jChannel)%bcmode)
484 case("D")
485 if (chanindexDynamic > 0) then
486 if (bias(iSensor)%chans(jChannel)%bctype=="C") &
487 bias(iSensor)%chans(jChannel)%coeff(1:npredictors) = coeffDynamic(satIndexDynamic,chanindexDynamic,1:npredictors)
488 if (bias(iSensor)%chans(jChannel)%bctype=="C" .or. bias(iSensor)%chans(jChannel)%bctype=="F") &
489 bias(iSensor)%chans(jChannel)%coeff_fov(1:nfov) = fovbiasDynamic(satIndexDynamic,chanindexDynamic,1:nfov)
490 else if (chanindexStatic > 0) then
491 if (bias(iSensor)%chans(jChannel)%bctype=="C") &
492 bias(iSensor)%chans(jChannel)%coeff(1:npredictors) = coeffStatic(satIndexStatic,chanindexStatic,1:npredictors)
493 if (bias(iSensor)%chans(jChannel)%bctype=="C" .or. bias(iSensor)%chans(jChannel)%bctype=="F") &
494 bias(iSensor)%chans(jChannel)%coeff_fov(1:nfov) = fovbiasStatic(satIndexStatic,chanindexStatic,1:nfov)
495 else
496 corrected = .false.
497 end if
498 case("S")
499 if (chanindexStatic > 0) then
500 if (bias(iSensor)%chans(jChannel)%bctype=="C") &
501 bias(iSensor)%chans(jChannel)%coeff(1:npredictors) = coeffStatic(satIndexStatic,chanindexStatic,1:npredictors)
502 if (bias(iSensor)%chans(jChannel)%bctype=="C" .or. bias(iSensor)%chans(jChannel)%bctype=="F") &
503 bias(iSensor)%chans(jChannel)%coeff_fov(1:nfov) = fovbiasStatic(satIndexStatic,chanindexStatic,1:nfov)
504 else
505 corrected = .false.
506 end if
507 end select
508
509 if (.not. corrected) then
510 write(*,*) "bcs_readCoeffs: Warning: channel ", bias(iSensor)%chans(jChannel)%channelNum, " of ", &
511 trim(instrName), " ", trim(satNamecoeff), " not corrected!"
512 end if
513
514 end do
515
516 end do
517
518 end if
519
520 end subroutine bcs_readCoeffs
521
522 !-----------------------------------------------------------------------
523 ! bcs_computePredictorBiases
524 !-----------------------------------------------------------------------
525 subroutine bcs_computePredictorBiases(obsSpaceData)
526 !
527 !:Purpose: to compute predictor average
528 !
529 implicit none
530
531 ! Arguments:
532 type(struct_obs), intent(inout) :: obsSpaceData
533
534 ! Locals:
535 real(8) :: predictor(NumPredictors)
536 integer :: iobs, nsize, i, j, npred
537 integer :: headerIndex, idatyp, indxtovs
538 integer :: iSensor, iFov, iPredictor, ierr
539 integer :: bodyIndex, jpred, chanIndx
540 real(8), allocatable :: temp_offset(:,:)
541 integer, allocatable :: temp_nobs(:)
542 real(8), allocatable :: temp_offset2(:,:,:)
543 integer, allocatable :: temp_nobs2(:,:)
544
545 if (centerPredictors) then
546 write(*,*) "bcs_computePredictorBiases: start"
547 npred = 0
548 do iSensor = 1, tvs_nSensors
549 npred = max(npred, maxval(bias(iSensor)%chans(:)%numActivePredictors))
550 end do
551 allocate(temp_offset2(tvs_nsensors,maxval(bias(:)%numChannels),2:npred))
552 allocate(temp_nobs2(tvs_nsensors,maxval(bias(:)%numChannels)))
553 temp_offset2(:,:,:) = 0.d0
554 temp_nobs2(:,:) = 0
555
556 call obs_set_current_header_list(obsSpaceData, 'TO')
557 iobs = 0
558 HEADER: do
559 headerIndex = obs_getHeaderIndex(obsSpaceData)
560 if (headerIndex < 0) exit HEADER
561
562 ! process only radiance data to be assimilated?
563 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
564 if (.not. tvs_isIdBurpTovs(idatyp)) then
565 write(*,*) 'bcs_computePredictorBiases: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
566 cycle HEADER
567 end if
568 iobs = iobs + 1
569
570 indxTovs = tvs_tovsIndex(headerIndex)
571 if (indxTovs < 0) cycle HEADER
572
573 iSensor = tvs_lsensor(indxTovs)
574
575 call obs_set_current_body_list(obsSpaceData, headerIndex)
576 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
577
578 BODY: do
579 bodyIndex = obs_getBodyIndex(obsSpaceData)
580 if (bodyIndex < 0) exit BODY
581
582 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
583
584 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
585 if (chanindx > 0) then
586 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
587 do iPredictor = 2, bias(iSensor)%chans(chanIndx)%NumActivePredictors
588 jPred = bias(iSensor)%chans(chanIndx)%PredictorIndex(iPredictor)
589 temp_offset2(iSensor,chanIndx,iPredictor) = temp_offset2(iSensor,chanIndx,iPredictor) + predictor(jPred)
590 end do
591 temp_nobs2(iSensor,chanIndx) = temp_nobs2(iSensor,chanIndx) + 1
592 end if
593 end do BODY
594 end do HEADER
595
596 allocate(temp_offset(maxval(bias(:)%numChannels),2:npred))
597 allocate(temp_nobs(maxval(bias(:)%numChannels)))
598
599 do iSensor = 1, tvs_nSensors
600 temp_offset(:,:) = 0.0d0
601 temp_offset(:,:) = temp_offset2(iSensor,:,:)
602 call mmpi_allreduce_sumR8_2d( temp_offset, "GRID" )
603
604 do i = 1, bias(iSensor)%numChannels
605 do j = 2, bias(iSensor)%chans(i)%numActivePredictors
606 bias(iSensor)%chans(i)%coeff_offset(j) = temp_offset(i,j)
607 end do
608 end do
609
610 temp_nobs(:) = 0
611 nsize = size(temp_nobs)
612 call rpn_comm_allreduce(temp_nobs2(iSensor,:), temp_nobs, nsize, "mpi_integer", &
613 "mpi_sum", "GRID", ierr)
614 if (ierr /= 0) then
615 call utl_abort("bcs_computePredictorBiases: Erreur de communication MPI 2")
616 end if
617
618 do i = 1, bias(iSensor)%numChannels
619 bias(iSensor)%chans(i)%coeff_nobs = temp_nobs(i)
620 end do
621 do i = 1, bias(iSensor)%numChannels
622 if (bias(iSensor)%chans(i)%coeff_nobs > 0) then
623 bias(iSensor)%chans(i)%coeff_offset(:) = bias(iSensor)%chans(i)%coeff_offset / bias(iSensor)%chans(i)%coeff_nobs
624 end if
625 end do
626 end do
627
628 deallocate(temp_offset)
629 deallocate(temp_nobs)
630 deallocate(temp_offset2)
631 deallocate(temp_nobs2)
632
633 write(*,*) "bcs_computePredictorBiases: end"
634 end if
635
636 end subroutine bcs_computePredictorBiases
637
638 !-----------------------------------------------------------------------
639 ! bcs_calcBias
640 !-----------------------------------------------------------------------
641 subroutine bcs_calcBias(obsSpaceData, columnTrlOnTrlLev)
642 !
643 !:Purpose: to fill OBS_BCOR column of ObsSpaceData body with bias correction computed from read coefficient file
644 !
645 implicit none
646
647 ! Arguments:
648 type(struct_obs), intent(inout) :: obsSpaceData
649 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
650
651 ! Locals:
652 integer :: headerIndex, bodyIndex, iobs, indxtovs, idatyp
653 integer :: iSensor, iPredictor, chanIndx
654 integer :: iScan, iFov, jPred
655 real(8) :: predictor(NumPredictors)
656 real(8) :: biasCor
657
658 if (.not. biasActive) return
659
660 write(*,*) "bcs_calcBias: start"
661
662 if (.not. allocated(trialHeight300m1000)) then
663 call bcs_getTrialPredictors(obsSpaceData, columnTrlOnTrlLev)
664 end if
665
666 iobs = 0
667 call obs_set_current_header_list(obsSpaceData, 'TO')
668 HEADER: do
669 headerIndex = obs_getHeaderIndex(obsSpaceData)
670 if (headerIndex < 0) exit HEADER
671
672 ! process only radiance data to be assimilated?
673 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
674 if (.not. tvs_isIdBurpTovs(idatyp)) then
675 write(*,*) 'bcs_calBias: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
676 cycle HEADER
677 end if
678
679 iobs = iobs + 1
680
681 indxtovs = tvs_tovsIndex(headerIndex)
682 if (indxtovs < 0) cycle HEADER
683
684 iSensor = tvs_lsensor(indxTovs)
685
686 call obs_set_current_body_list(obsSpaceData, headerIndex)
687 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
688
689 if (bias(iSensor)%numScan > 1) then
690 iScan = iFov
691 else
692 iScan = 1
693 end if
694
695 BODY: do
696 bodyIndex = obs_getBodyIndex(obsSpaceData)
697 if (bodyIndex < 0) exit BODY
698
699 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
700 if (obs_bodyElem_r(obsSpaceData, OBS_VAR, bodyIndex) == MPC_missingValue_R8) cycle BODY
701
702 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
703 if (chanindx > 0) then
704 if (bias(iSensor)%chans(chanIndx)%isDynamic .and. bias(iSensor)%numScan >0) then
705 if ( bias(iSensor)%chans(chanIndx)%coeff_fov(iScan)/= MPC_missingValue_R8 .and. &
706 all( bias(iSensor)%chans(chanIndx)%coeff(1:bias(iSensor)%chans(chanIndx)%NumActivePredictors)/= MPC_missingValue_R8) ) then
707 biasCor = bias(iSensor)%chans(chanIndx)%coeff_fov(iScan) + &
708 bias(iSensor)%chans(chanIndx)%coeff(1)
709 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
710 do iPredictor = 2, bias(iSensor)%chans(chanIndx)%NumActivePredictors
711 jPred = bias(iSensor)%chans(chanIndx)%PredictorIndex(iPredictor)
712 biasCor = biasCor + predictor(jPred) * bias(iSensor)%chans(chanIndx)%coeff(iPredictor)
713 end do
714 biasCor = -1.d0 * biascor
715 call obs_bodySet_r( obsSpaceData, OBS_BCOR, bodyIndex, biasCor)
716 end if
717 end if
718 end if
719 end do BODY
720 end do HEADER
721
722 write(*,*) "bcs_calcBias: end"
723
724 end subroutine bcs_calcBias
725
726 !-----------------------------------------------------------------------
727 ! bcs_dumpBiasToSqliteAfterThinning
728 !-----------------------------------------------------------------------
729 subroutine bcs_dumpBiasToSqliteAfterThinning(obsSpaceData)
730 !
731 !:Purpose: to dump bias correction coefficients and predictors in dedicated sqlite files
732 !
733 implicit none
734
735 ! Arguments:
736 type(struct_obs), intent(inout) :: obsSpaceData
737
738 ! Locals:
739 integer :: headerIndex, bodyIndex,iobs, indxtovs, idatyp
740 integer :: sensorIndex, iPredictor, chanIndx, codeTypeIndex, fileIndex, searchIndex
741 integer :: iScan, iFov, jPred, burpChanIndex
742 real(8) :: predictor(NumPredictors)
743 real(8) :: biasCor
744 real(8) :: sunzen, sunaz, satzen, sataz
745 type(fSQL_DATABASE), allocatable :: db(:) ! SQLIte file handle
746 type(fSQL_STATEMENT), allocatable :: stmtPreds(:), stmtCoeffs(:) ! precompiled SQLite statements
747 type(fSQL_STATUS) :: stat ! SQLiteerror status
748 character(len=512) :: queryCreate, queryPreds, queryCoeffs, queryTrim
749 logical, allocatable :: first(:)
750 integer, allocatable :: fileIndexes(:), obsOffset(:), dataOffset(:)
751 character(len=*), parameter :: myName = 'bcs_dumpBiasToSqliteAfterThinning::'
752 character(len=30) :: fileNameExtension
753 character(len=4) :: cmyidx, cmyidy
754 integer :: tovsCodeTypeListSize, tovsCodeTypeList(ninst)
755 integer :: tovsFileNameListSize
756 character(len=20) :: tovsFileNameList(30)
757 character(len=256) :: fileName
758 integer :: tovsAllCodeTypeListSize, tovsAllCodeTypeList(ninst)
759
760 if (.not. biasActive) return
761 if (.not. dumpToSqliteAfterThinning) return
762
763 write(*,*) "bcs_dumpBiasToSqliteAfterThinning: start"
764
765 ! get list of all possible tovs codetype values and unique list of corresponding filenames
766 call tvs_getAllIdBurpTovs(tovsAllCodeTypeListSize, tovsAllCodeTypeList)
767 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsAllCodeTypeListSize = ', tovsAllCodeTypeListSize
768 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsAllCodeTypeList = ', tovsAllCodeTypeList(1:tovsAllCodeTypeListSize)
769
770 tovsFileNameListSize = 0
771 tovsFileNameList(:) = 'XXXXX'
772 do codeTypeIndex = 1, tovsAllCodeTypeListSize
773 fileName = getObsFileName(tovsAllCodeTypeList(codeTypeIndex))
774 if (all(tovsFileNameList(:) /= fileName)) then
775 tovsFileNameListSize = tovsFileNameListSize + 1
776 tovsFileNameList(tovsFileNameListSize) = fileName
777 end if
778 end do
779 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsFileNameListSize = ', tovsFileNameListSize
780 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsFileNameList = ', tovsFileNameList(1:tovsFileNameListSize)
781
782 allocate(db(tovsFileNameListSize))
783 allocate(stmtPreds(tovsFileNameListSize))
784 allocate(stmtCoeffs(tovsFileNameListSize))
785 allocate(first(tovsFileNameListSize))
786 first(:) = .true.
787 allocate(fileIndexes(size(obsf_fileName)))
788 fileIndexes(:) = -1
789 do fileIndex = 1, tovsFileNameListSize
790 do searchIndex = 1, size(obsf_fileName)
791 if (index(trim(obsf_fileName(searchIndex)), trim(tovsFileNameList(fileIndex))) >0) then
792 fileIndexes(searchIndex) = fileIndex
793 end if
794 end do
795 end do
796 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: fileIndexes', fileIndexes(1:tovsFileNameListSize)
797 allocate(obsOffset(tovsFileNameListSize))
798 allocate(dataOffset(tovsFileNameListSize))
799 do fileIndex = 1, tovsFileNameListSize
800 fileName = tovsFileNameList(fileIndex)
801 write(*,*) 'tovs filename = ', fileName
802 ! get list of codetypes associated with this filename
803 tovsCodeTypeListSize = 0
804 tovsCodeTypeList(:) = MPC_missingValue_INT
805 do codeTypeIndex = 1, tovsAllCodeTypeListSize
806 if (fileName == getObsFileName(tovsAllCodeTypeList(codeTypeIndex))) then
807 tovsCodeTypeListSize = tovsCodeTypeListSize + 1
808 tovsCodeTypeList(tovsCodeTypeListSize) = tovsAllCodeTypeList(codeTypeIndex)
809 end if
810 end do
811
812 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsCodeTypeListSize = ', tovsCodeTypeListSize
813 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: tovsCodeTypeList = ', tovsCodeTypeList(1:tovsCodeTypeListSize)
814 call getInitialIdObsData(obsSpaceData, 'TO', obsOffset(fileIndex), dataOffset(fileIndex), &
815 codeTypeList_opt=tovsCodeTypeList(1:tovsCodeTypeListSize))
816 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: obsOffset(fileIndex), dataOffset(fileIndex)', fileIndex, obsOffset(fileIndex), dataOffset(fileIndex)
817 end do
818
819 iobs = 0
820 call obs_set_current_header_list(obsSpaceData, 'TO')
821 HEADER: do
822 headerIndex = obs_getHeaderIndex(obsSpaceData)
823 if (headerIndex < 0) exit HEADER
824 ! process only radiance data to be assimilated?
825 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
826 if (.not. tvs_isIdBurpTovs(idatyp)) then
827 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
828 cycle HEADER
829 end if
830 iobs = iobs + 1
831 fileIndex = fileIndexes(obs_headElem_i(obsSpaceData, OBS_IDF, headerIndex))
832 indxtovs = tvs_tovsIndex(headerIndex)
833 if (indxtovs < 0) cycle HEADER
834 sensorIndex = tvs_lsensor(indxTovs)
835 if (first(fileIndex)) then
836 if (obs_mpiLocal(obsSpaceData)) then
837 write(cmyidy,'(i4.4)') (mmpi_myidy + 1)
838 write(cmyidx,'(i4.4)') (mmpi_myidx + 1)
839 fileNameExtension = trim(cmyidx) // '_' // trim(cmyidy)
840 else
841 fileNameExtension = ' '
842 end if
843
844 fileName = 'obs/bcr' // trim(tovsFileNameList(fileIndex)) &
845 // '_' // trim(filenameExtension)
846
847 call fSQL_open(db(fileIndex), fileName, stat)
848 write(*,*) 'bcs_dumpBiasToSqliteAfterThinning: Open ', trim(fileName)
849 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_open: ')
850
851 ! Create the tables
852 queryCreate = 'CREATE TABLE predictors(id_data integer, id_obs integer, predIndex integer, PredictorValue real,' // &
853 'PredictorType varchar(2), bcor real, fov integer, sunzen real, sunaz real, satzen real, sataz real);' // &
854 'CREATE TABLE coeffs2(predIndex integer, coeff real, instrument varchar(10), platform varchar(16), vcoord integer, fov integer);'
855 call fSQL_do_many(db(fileIndex), queryCreate, stat)
856 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_do_many: ')
857
858 queryPreds = 'insert into predictors (id_data, id_obs, predIndex, predictorValue,' // &
859 ' predictorType, bcor, fov, sunzen, sunaz, satzen, sataz) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);'
860 queryCoeffs = 'insert into coeffs2 (predIndex, coeff, instrument, platform, vcoord, fov) values(?, ?, ?, ?, ?, ?); '
861 write(*,*) myName // ' Insert query Predictors = ', trim(queryPreds)
862 write(*,*) myName // ' Insert query Coeffs = ', trim(queryCoeffs)
863 call fSQL_begin(db(fileIndex))
864 call fSQL_prepare(db(fileIndex), queryPreds, stmtPreds(fileIndex), stat)
865 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_prepare 1: ')
866 call fSQL_prepare(db(fileIndex), queryCoeffs, stmtCoeffs(fileIndex), stat)
867 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_prepare 2: ')
868 first(fileIndex) = .false.
869 end if
870 call obs_set_current_body_list(obsSpaceData, headerIndex)
871 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
872 sunzen = obs_headElem_r(obsSpaceData, OBS_SUN, headerIndex)
873 sunaz = obs_headElem_r(obsSpaceData, OBS_SAZ, headerIndex)
874 satzen = obs_headElem_r(obsSpaceData, OBS_SZA, headerIndex)
875 sataz = obs_headElem_r(obsSpaceData, OBS_AZA, headerIndex)
876 if (bias(sensorIndex)%numScan > 1) then
877 iScan = iFov
878 else
879 iScan = 1
880 end if
881 BODY: do
882 bodyIndex = obs_getBodyIndex(obsSpaceData)
883 if (bodyIndex < 0) exit BODY
884 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
885 if (obs_bodyElem_r(obsSpaceData, OBS_VAR, bodyIndex) == MPC_missingValue_R8) cycle BODY
886 if (btest(obs_bodyElem_i(obsSpaceData, OBS_FLG, bodyIndex), 11)) cycle BODY
887 call bcs_getChannelIndex(obsSpaceData, sensorIndex, chanIndx, bodyIndex)
888 if (chanindx > 0) then
889 biasCor = 0.0d0
890 if (bias(sensorIndex)%chans(chanIndx)%isDynamic .and. bias(sensorIndex)%numScan > 0) then
891 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
892 biasCor = bias(sensorIndex)%chans(chanIndx)%coeff_fov(iScan) + &
893 bias(sensorIndex)%chans(chanIndx)%coeff(1)
894 burpChanIndex = nint(obs_bodyElem_r(obsSpaceData, OBS_PPP, bodyIndex))
895 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=1, int_var=0)
896 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=2, real8_var=bias(sensorIndex)%chans(chanIndx)%coeff_fov(iScan))
897 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=3, char_var=trim(tvs_instrumentName(sensorIndex)))
898 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=4, char_var=trim(tvs_satelliteName(sensorIndex)))
899 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=5, int_var=burpChanIndex)
900 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=6, int_var=iScan)
901 call fSQL_exec_stmt(stmtCoeffs(fileIndex))
902 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=1, int_var=1)
903 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=2, real8_var=bias(sensorIndex)%chans(chanIndx)%coeff(1))
904 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=3, char_var=trim(tvs_instrumentName(sensorIndex)))
905 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=4, char_var=trim(tvs_satelliteName(sensorIndex)))
906 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=5, int_var=burpChanIndex)
907 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=6, int_var=iScan)
908 call fSQL_exec_stmt(stmtCoeffs(fileIndex))
909 do iPredictor = 2, bias(sensorIndex)%chans(chanIndx)%NumActivePredictors
910 jPred = bias(sensorIndex)%chans(chanIndx)%PredictorIndex(iPredictor)
911 biasCor = biasCor + predictor(jPred) * bias(sensorIndex)%chans(chanIndx)%coeff(iPredictor)
912 end do
913 end if
914 biasCor = -1.d0 * biascor
915 do iPredictor = 2, bias(sensorIndex)%chans(chanIndx)%NumActivePredictors
916 jPred = bias(sensorIndex)%chans(chanIndx)%PredictorIndex(iPredictor)
917 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=1, int_var=jPred)
918 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=2, real8_var=bias(sensorIndex)%chans(chanIndx)%coeff(iPredictor))
919 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=3, char_var=trim(tvs_instrumentName(sensorIndex)))
920 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=4, char_var=trim(tvs_satelliteName(sensorIndex)))
921 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=5, int_var=burpChanIndex)
922 call fSQL_bind_param(stmtCoeffs(fileIndex), param_index=6, int_var=iScan)
923 call fSQL_exec_stmt (stmtCoeffs(fileIndex))
924 call fSQL_bind_param(stmtPreds(fileIndex), param_index=1, int_var=bodyIndex + dataOffset(fileIndex))
925 call fSQL_bind_param(stmtPreds(fileIndex), param_index=2, int_var=headerIndex + obsOffset(fileIndex))
926 call fSQL_bind_param(stmtPreds(fileIndex), param_index=3, int_var=jPred)
927 call fSQL_bind_param(stmtPreds(fileIndex), param_index=4, real8_var=predictor(jPred))
928 call fSQL_bind_param(stmtPreds(fileIndex), param_index=5, char_var=predtab(jPred))
929 call fSQL_bind_param(stmtPreds(fileIndex), param_index=6, real8_var=biascor)
930 call fSQL_bind_param(stmtPreds(fileIndex), param_index=7, int_var=iScan)
931 call fSQL_bind_param(stmtPreds(fileIndex), param_index=8, real8_var=sunzen)
932 call fSQL_bind_param(stmtPreds(fileIndex), param_index=9, real8_var=sunaz )
933 call fSQL_bind_param(stmtPreds(fileIndex), param_index=10, real8_var=satzen )
934 call fSQL_bind_param(stmtPreds(fileIndex), param_index=11, real8_var=sataz)
935 call fSQL_exec_stmt (stmtPreds(fileIndex))
936 end do
937 end if
938 end do BODY
939 end do HEADER
940 do fileIndex = 1, tovsFileNameListSize
941 if (.not. first(fileIndex)) then
942 call fSQL_finalize(stmtCoeffs(fileIndex))
943 call fSQL_finalize(stmtPreds(fileIndex))
944 queryTrim = 'create table coeffs as select distinct * from coeffs2; drop table coeffs2;'
945 call fSQL_do_many(db(fileIndex), queryTrim, stat)
946 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_do_many: ')
947 call fSQL_commit(db(fileIndex), stat)
948 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_commit: ')
949 call fSQL_close(db(fileIndex), stat)
950 if (fSQL_error(stat) /= FSQL_OK) call handleError(stat, 'fSQL_close: ')
951 end if
952 end do
953 deallocate(dataOffset)
954 deallocate(obsOffset)
955 deallocate(fileIndexes)
956 deallocate(first)
957 deallocate(stmtCoeffs)
958 deallocate(stmtPreds)
959 deallocate(db)
960 write(*,*) "bcs_dumpBiasToSqliteAfterThinning: end"
961 contains
962
963 subroutine handleError(stat, message)
964 implicit none
965
966 ! Arguments:
967 type(FSQL_STATUS), intent(in) :: stat
968 character(len=*), intent(in) :: message
969
970 write(*,*) message, fSQL_errmsg(stat)
971 call utl_abort(trim(message))
972 end subroutine handleError
973
974 end subroutine bcs_dumpBiasToSqliteAfterThinning
975
976 !---------------------------------------
977 ! bcs_computeResidualsStatistics
978 !----------------------------------------
979 subroutine bcs_computeResidualsStatistics(obsSpaceData, prefix)
980 !
981 !:Purpose: to compute residuals mean and standard deviation by intrument, channel and scan position
982 !
983 implicit none
984
985 ! Arguments:
986 type(struct_obs), intent(inout) :: obsSpaceData
987 character(len=*), intent(in) :: prefix
988
989 ! Locals:
990 real(8), allocatable :: tbias(:,:), tstd(:,:)
991 integer, allocatable :: tcount(:,:)
992 real(8), allocatable :: biasMpiGlobal(:,:), stdMpiGLobal(:,:)
993 integer, allocatable :: countMpiGlobal(:,:)
994 integer :: sensorIndex, headerIndex, bodyIndex
995 integer :: nchans, nscan
996 integer :: iSensor, iScan, chanIndx, iFov
997 real(8) :: OmF, bcor
998 integer :: ierr, nulfile1, nulfile2
999 character(len=10) :: instrName, satNamecoeff
1000 character(len=72) :: errorMessage
1001
1002 if (.not. biasActive) return
1003
1004 if (.not. outstats) return
1005
1006 write(*,*) "bcs_computeResidualsStatistics: start"
1007
1008 SENSORS:do sensorIndex = 1, tvs_nsensors
1009
1010 if (.not. tvs_isReallyPresentMpiGLobal(sensorIndex)) cycle SENSORS
1011
1012 write(*,*) "bcs_computeResidualsStatistics: sensorIndex ", sensorIndex
1013
1014 nchans = bias(sensorIndex)%numChannels
1015 nscan = bias(sensorIndex)%numscan
1016
1017 allocate(tbias(nchans,nscan))
1018 tbias(:,:) = 0.d0
1019 allocate(tstd(nchans,nscan))
1020 tstd(:,:) = 0.d0
1021 allocate(tcount(nchans,nscan))
1022 tcount(:,:) = 0
1023
1024 call obs_set_current_header_list(obsSpaceData, 'TO')
1025
1026 HEADER: do
1027 headerIndex = obs_getHeaderIndex(obsSpaceData)
1028 if (headerIndex < 0) exit HEADER
1029 if (tvs_tovsIndex(headerIndex) < 0) cycle HEADER
1030 iSensor = tvs_lsensor(tvs_tovsIndex(headerIndex))
1031 if (iSensor /= sensorIndex) cycle HEADER
1032
1033 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
1034 if (nscan > 1) then
1035 iScan = iFov
1036 else
1037 iScan = 1
1038 end if
1039
1040 call obs_set_current_body_list(obsSpaceData, headerIndex)
1041 BODY: do
1042 bodyIndex = obs_getBodyIndex(obsSpaceData)
1043 if (bodyIndex < 0) exit BODY
1044
1045 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
1046 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
1047 if (chanindx > 0) then
1048 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
1049 bcor = obs_bodyElem_r(obsSpaceData, OBS_BCOR, bodyIndex)
1050 if (OmF /= MPC_missingValue_R8 .and. bcor /= MPC_missingValue_R8) then
1051 tbias(chanIndx,iScan) = tbias(chanIndx,iScan) + (OmF + bcor)
1052 tstd(chanIndx,iScan) = tstd(chanIndx,iScan) + (OmF + bcor) ** 2
1053 tcount(chanIndx,iScan) = tcount(chanIndx,iScan) + 1
1054 end if
1055 end if
1056 end do BODY
1057 end do HEADER
1058
1059 allocate( biasMpiGlobal(nchans,nscan) )
1060 allocate( stdMpiGlobal(nchans,nscan) )
1061 allocate( countMpiGlobal(nchans,nscan) )
1062
1063 call mmpi_reduce_sumR8_2d( tbias, biasMpiGlobal, 0, "GRID" )
1064 call mmpi_reduce_sumR8_2d( tstd, stdMpiGlobal, 0, "GRID" )
1065 call rpn_comm_reduce(tcount, countMpiGlobal, size(countMpiGlobal), "mpi_integer", "MPI_SUM", 0, "GRID", ierr)
1066 if (ierr /=0) then
1067 write(errorMessage,*) "bcs_computeResidualsStatistics: MPI communication error 3", ierr
1068 call utl_abort(errorMessage)
1069 end if
1070
1071 if (mmpi_myId == 0) then
1072 where(countMpiGlobal > 0)
1073 biasMpiGlobal = biasMpiGlobal / countMpiGlobal
1074 stdMpiGlobal = sqrt(stdMpiGlobal/ countMpiGlobal - biasMpiGlobal**2)
1075 end where
1076
1077 instrName = InstrNametoCoeffFileName(tvs_instrumentName(sensorIndex))
1078 satNamecoeff = SatNameinCoeffFile(tvs_satelliteName(sensorIndex))
1079
1080 nulfile1 = 0
1081 ierr = fnom(nulfile1, './std_' // trim(instrName) // '_' // trim(satNamecoeff) // trim(prefix) // '.dat', 'FTN+FMT', 0)
1082 nulfile2 = 0
1083 ierr = fnom(nulfile2, './mean_' // trim(instrName) // '_' // trim(satNamecoeff) // trim(prefix) // '.dat', 'FTN+FMT', 0)
1084
1085 do chanIndx = 1, nchans
1086 if (sum(countMpiGlobal(chanIndx, :)) > 0) then
1087 write(nulfile2,'(i4,1x,100e14.6)') chanIndx, biasMpiGlobal(chanindx,:)
1088 write(nulfile1,'(i4,1x,100e14.6)') chanIndx, stdMpiGlobal(chanindx,:)
1089 end if
1090 end do
1091 ierr = fclos(nulfile1)
1092 ierr = fclos(nulfile2)
1093
1094 end if
1095
1096 deallocate(biasMpiGlobal)
1097 deallocate(stdMpiGlobal)
1098 deallocate(countMpiGlobal)
1099 deallocate(tbias)
1100 deallocate(tstd)
1101 deallocate(tcount)
1102
1103 end do SENSORS
1104
1105 write(*,*) "bcs_computeResidualsStatistics: end"
1106
1107 end subroutine bcs_computeResidualsStatistics
1108
1109 !---------------------------------------
1110 ! bcs_removeOutliers
1111 !----------------------------------------
1112 subroutine bcs_removeOutliers(obsSpaceData)
1113 !
1114 !:Purpose: to remove outliers (too large OmF) from linear regression
1115 !
1116 implicit none
1117
1118 ! Arguments:
1119 type(struct_obs), intent(inout) :: obsSpaceData
1120
1121 ! Locals:
1122 real(8), allocatable :: tbias(:,:), tstd(:,:)
1123 integer, allocatable :: tcount(:,:)
1124 real(8), allocatable :: biasMpiGlobal(:,:), stdMpiGLobal(:,:)
1125 integer, allocatable :: countMpiGlobal(:,:)
1126 integer :: sensorIndex, headerIndex, bodyIndex
1127 integer :: nchans, nfiles
1128 integer :: iSensor, chanIndx, timeIndex
1129 real(8) :: OmF
1130 real(8), parameter :: alpha = 5.d0
1131 real(8) :: stepObsIndex
1132 integer :: ierr
1133 character(len=72) :: errorMessage
1134
1135 if (.not. biasActive) return
1136
1137 write(*,*) "bcs_removeOutliers: start"
1138
1139 SENSORS:do sensorIndex = 1, tvs_nsensors
1140
1141 if (.not. tvs_isReallyPresentMpiGLobal(sensorIndex)) cycle SENSORS
1142
1143 write(*,*) "bcs_removeOutliers: sensorIndex ", sensorIndex
1144
1145 nchans = bias(sensorIndex)%numChannels
1146 nfiles = tim_nstepobs
1147
1148 allocate(tbias(nchans,nfiles))
1149 tbias(:,:) = 0.d0
1150 allocate(tstd(nchans,nfiles))
1151 tstd(:,:) = 0.d0
1152 allocate(tcount(nchans,nfiles))
1153 tcount(:,:) = 0
1154
1155 call obs_set_current_header_list(obsSpaceData, 'TO')
1156
1157 HEADER1: do
1158 headerIndex = obs_getHeaderIndex(obsSpaceData)
1159 if (headerIndex < 0) exit HEADER1
1160 if (tvs_tovsIndex(headerIndex) < 0) cycle HEADER1
1161 iSensor = tvs_lsensor(tvs_tovsIndex(headerIndex))
1162 if (iSensor /= sensorIndex) cycle HEADER1
1163
1164 call tim_getStepObsIndex(stepObsIndex, tim_getDatestamp(), &
1165 obs_headElem_i(obsSpaceData, OBS_DAT, headerIndex), &
1166 obs_headElem_i(obsSpaceData, OBS_ETM, headerIndex), tim_nstepobs)
1167
1168 timeIndex = nint(stepObsIndex)
1169 if (timeIndex < 0) cycle HEADER1
1170 call obs_set_current_body_list(obsSpaceData, headerIndex)
1171 BODY1: do
1172 bodyIndex = obs_getBodyIndex(obsSpaceData)
1173 if (bodyIndex < 0) exit BODY1
1174
1175 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated .and. &
1176 .not. btest(obs_bodyElem_i(obsSpaceData, OBS_FLG, bodyIndex), 6)) then
1177 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
1178 if (chanindx > 0) then
1179 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
1180 if (OmF /= MPC_missingValue_R8) then
1181 tbias(chanIndx,timeindex) = tbias(chanIndx,timeindex) + OmF
1182 tstd(chanIndx,timeindex) = tstd(chanIndx,timeindex) + (OmF ** 2)
1183 tcount(chanIndx,timeindex) = tcount(chanIndx,timeindex) + 1
1184 end if
1185 end if
1186 end if
1187 end do BODY1
1188 end do HEADER1
1189
1190 allocate(biasMpiGlobal(nchans,nfiles))
1191 allocate(stdMpiGlobal(nchans,nfiles))
1192 allocate(countMpiGlobal(nchans,nfiles))
1193
1194 call mmpi_reduce_sumR8_2d( tbias, biasMpiGlobal, 0, "GRID" )
1195 call mmpi_reduce_sumR8_2d( tstd, stdMpiGlobal, 0, "GRID" )
1196 call rpn_comm_reduce(tcount, countMpiGlobal, size(countMpiGlobal), "mpi_integer", "MPI_SUM", 0, "GRID", ierr)
1197 if (ierr /=0) then
1198 write(errorMessage,*) "bcs_removeOutliers: MPI communication error 3", ierr
1199 call utl_abort(errorMessage)
1200 end if
1201
1202 if (mmpi_myId == 0) then
1203 where(countMpiGlobal > 0)
1204 biasMpiGlobal = biasMpiGlobal / countMpiGlobal
1205 stdMpiGlobal = sqrt(stdMpiGlobal/ countMpiGlobal - biasMpiGlobal**2)
1206 end where
1207 end if
1208
1209 call rpn_comm_bcast(countMpiGlobal, nchans*nfiles, "mpi_integer", 0, "GRID", ierr)
1210 if (ierr /=0) then
1211 write(errorMessage,*) "bcs_removeOutliers: MPI communication error 4", ierr
1212 call utl_abort(errorMessage)
1213 end if
1214 call rpn_comm_bcast(stdMpiGlobal, nchans*nfiles, "mpi_double_precision", 0, "GRID", ierr)
1215 if (ierr /=0) then
1216 write(errorMessage,*) "bcs_removeOutliers: MPI communication error 5", ierr
1217 call utl_abort(errorMessage)
1218 end if
1219
1220 if (sum(countMpiGlobal) /= 0) then
1221
1222 tcount(:,:) = 0
1223
1224 call obs_set_current_header_list(obsSpaceData, 'TO')
1225
1226 HEADER2: do
1227 headerIndex = obs_getHeaderIndex(obsSpaceData)
1228 if (headerIndex < 0) exit HEADER2
1229 if (tvs_tovsIndex(headerIndex) < 0) cycle HEADER2
1230 iSensor = tvs_lsensor(tvs_tovsIndex(headerIndex))
1231 if (iSensor /= sensorIndex) cycle HEADER2
1232
1233 call tim_getStepObsIndex(stepObsIndex, tim_getDatestamp(), &
1234 obs_headElem_i(obsSpaceData, OBS_DAT, headerIndex), &
1235 obs_headElem_i(obsSpaceData, OBS_ETM, headerIndex), tim_nstepobs)
1236
1237 timeIndex = nint(stepObsIndex)
1238 if (timeIndex < 0) cycle HEADER2
1239
1240 call obs_set_current_body_list(obsSpaceData, headerIndex)
1241 BODY2: do
1242 bodyIndex = obs_getBodyIndex(obsSpaceData)
1243 if (bodyIndex < 0) exit BODY2
1244
1245 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated .and. &
1246 .not. btest(obs_bodyElem_i(obsSpaceData, OBS_FLG, bodyIndex), 6)) then
1247
1248 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
1249
1250 if (chanindx > 0) then
1251
1252 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
1253 if (countMpiGlobal(chanIndx, timeindex) > 2 .and. &
1254 abs(OmF) > alpha * stdMpiGlobal(chanIndx, timeindex)) then
1255 call obs_bodySet_i(obsSpaceData, OBS_ASS, bodyIndex, obs_notAssimilated)
1256 tcount(chanIndx,timeindex) = tcount(chanIndx,timeindex) + 1
1257 end if
1258
1259 end if
1260 end if
1261 end do BODY2
1262 end do HEADER2
1263
1264 do chanIndx = 1, nchans
1265 if (sum(tcount(chanIndx,:)) > 0) then
1266 write(*,'(A,1x,i2,1x,i4,1x,i6,1x,30e14.6)') "bcs_removeOutliers:", sensorindex, chanIndx, sum(tcount(chanIndx,:)), stdMpiGlobal(chanIndx,:)
1267 end if
1268 end do
1269
1270 end if
1271
1272 deallocate(biasMpiGlobal)
1273 deallocate(stdMpiGlobal)
1274 deallocate(countMpiGlobal)
1275 deallocate(tbias)
1276 deallocate(tstd)
1277 deallocate(tcount)
1278
1279 end do SENSORS
1280
1281 write(*,*) "bcs_removeOutliers: end"
1282
1283 end subroutine bcs_removeOutliers
1284
1285 !---------------------------------------
1286 ! bcs_calcBias_tl
1287 !----------------------------------------
1288 subroutine bcs_calcBias_tl(cv_in, obsColumnIndex, obsSpaceData, columnTrlOnTrlLev)
1289 !
1290 !:Purpose: tl of bias computation (for varBC)
1291 !
1292 implicit none
1293
1294 ! Arguments:
1295 real(8), intent(in) :: cv_in(:)
1296 integer, intent(in) :: obsColumnIndex
1297 type(struct_obs), intent(inout) :: obsSpaceData
1298 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
1299
1300 ! Locals:
1301 integer :: headerIndex, bodyIndex, iobs, indxtovs, idatyp
1302 integer :: iSensor, iPredictor, chanIndx
1303 integer :: iScan, iFov, jPred
1304 real(8) :: predictor(NumPredictors)
1305 real(8), pointer :: cv_bias(:)
1306 real(8), target :: dummy4Pointer(1)
1307 real(8) :: biasCor
1308
1309 if (.not. biasActive) return
1310
1311 if (.not. allocated(trialHeight300m1000)) then
1312 call bcs_getTrialPredictors(obsSpaceData, columnTrlOnTrlLev)
1313 call bcs_computePredictorBiases(obsSpaceData)
1314 call bcs_getRadiosondeWeight(obsSpaceData, lmodify_obserror_opt=.true.)
1315 end if
1316
1317 nullify(cv_bias)
1318 if (mmpi_myid == 0) then
1319 if (cvm_subVectorExists('BIAS')) then
1320 cv_Bias => cvm_getSubVector(cv_in, 'BIAS')
1321 write(*,*) 'bcs_calcBias_tl: maxval(cv_bias) = ', maxval(cv_bias(:))
1322 else
1323 write(*,*) 'bcs_calcBias_tl: control vector does not include bias coefficients'
1324 return
1325 end if
1326 else
1327 cv_bias => dummy4Pointer
1328 end if
1329
1330 ! get bias coefficients
1331 call bcs_cvToCoeff(cv_bias)
1332
1333 ! apply bias increment to specified obs column
1334 iobs = 0
1335 call obs_set_current_header_list(obsSpaceData, 'TO')
1336 HEADER: do
1337 headerIndex = obs_getHeaderIndex(obsSpaceData)
1338 if (headerIndex < 0) exit HEADER
1339
1340 ! process only radiance data to be assimilated?
1341 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
1342 if (.not. tvs_isIdBurpTovs(idatyp)) then
1343 write(*,*) 'bcs_calBias_tl: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
1344 cycle HEADER
1345 end if
1346
1347 iobs = iobs + 1
1348
1349 indxtovs = tvs_tovsIndex(headerIndex)
1350 if (indxtovs < 0) cycle HEADER
1351
1352 iSensor = tvs_lsensor(indxTovs)
1353
1354 call obs_set_current_body_list(obsSpaceData, headerIndex)
1355 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
1356
1357 BODY: do
1358 bodyIndex = obs_getBodyIndex(obsSpaceData)
1359 if (bodyIndex < 0) exit BODY
1360
1361 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
1362
1363 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
1364
1365 if (chanindx > 0) then
1366 biasCor = 0.0d0
1367 if (bias(iSensor)%chans(chanIndx)%isDynamic .and. bias(iSensor)%numScan >0) then
1368 call bcs_getPredictors(predictor, headerIndex, iobs, chanindx, obsSpaceData)
1369 do iPredictor = 1, bias(iSensor)%chans(chanIndx)%NumActivePredictors
1370 jPred = bias(iSensor)%chans(chanIndx)%PredictorIndex(iPredictor)
1371 if (iPredictor == 1) then
1372 if (bias(iSensor)%numScan > 1) then
1373 iScan = iFov
1374 else
1375 iScan = 1
1376 end if
1377 biasCor = biasCor + predictor(jPred) * bias(iSensor)%chans(chanIndx)%coeffIncr_fov(iScan)
1378 else
1379 biasCor = biasCor + predictor(jPred) * bias(iSensor)%chans(chanIndx)%coeffIncr(iPredictor)
1380 end if
1381 end do
1382 end if
1383 call obs_bodySet_r(obsSpaceData, obsColumnIndex, bodyIndex, &
1384 obs_bodyElem_r(obsSpaceData, obsColumnIndex, bodyIndex) - biasCor)
1385 end if
1386 end do BODY
1387 end do HEADER
1388
1389
1390 end subroutine bcs_calcBias_tl
1391
1392 !----------------------
1393 ! bcs_getTrialPredictors
1394 !----------------------
1395 subroutine bcs_getTrialPredictors(obsSpaceData, columnTrlOnTrlLev)
1396 !
1397 !:Purpose: get predictors from trial fields
1398 !
1399 implicit none
1400
1401 ! Arguments:
1402 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
1403 type(struct_obs), intent(inout) :: obsSpaceData
1404
1405 ! Locals:
1406 integer :: headerIndex, idatyp, iobs
1407 real(8) :: height1, height2
1408
1409 if (tvs_nobtov > 0) then
1410 allocate(trialHeight300m1000(tvs_nobtov))
1411 allocate(trialHeight50m200(tvs_nobtov))
1412 allocate(trialHeight5m50(tvs_nobtov))
1413 allocate(trialHeight1m10(tvs_nobtov))
1414 allocate(trialTG(tvs_nobtov))
1415 allocate(RadiosondeWeight(tvs_nobtov))
1416 else
1417 write(*,*) 'bcs_getTrialPredictors: No radiance OBS found'
1418 return
1419 end if
1420
1421 iobs = 0
1422
1423 call obs_set_current_header_list(obsSpaceData, 'TO')
1424
1425 HEADER2: do
1426 headerIndex = obs_getHeaderIndex(obsSpaceData)
1427 if (headerIndex < 0) exit HEADER2
1428 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
1429 if (.not. tvs_isIdBurpTovs(idatyp)) then
1430 write(*,*) 'bcs_getTrialPredictors: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
1431 cycle HEADER2
1432 end if
1433 iobs = iobs + 1
1434
1435 height1 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 1000.d0)
1436 height2 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 300.d0)
1437
1438 trialHeight300m1000(iobs) = height2 - height1
1439
1440 height1 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 200.d0)
1441 height2 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 50.d0)
1442
1443 trialHeight50m200(iobs) = height2 - height1
1444
1445 height1 = height2
1446 height2 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 5.d0)
1447
1448 trialHeight5m50(iobs) = height2 - height1
1449
1450 height1 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 10.d0)
1451 height2 = logInterpHeight(columnTrlOnTrlLev, headerIndex, 1.d0)
1452
1453 trialHeight1m10(iobs) = height2 - height1
1454
1455 trialTG(iobs) = col_getElem(columnTrlOnTrlLev, 1, headerIndex, 'TG')
1456
1457 end do HEADER2
1458
1459 if (trialTG(1) > 150.0d0) then
1460 write(*,*) 'bcs_getTrialPredictors: converting TG from Kelvin to deg_C'
1461 trialTG(:) = trialTG(:) - MPC_K_C_DEGREE_OFFSET_R8
1462 end if
1463
1464 trialHeight300m1000(:) = 0.1d0 * trialHeight300m1000(:) ! conversion factor
1465 trialHeight50m200(:) = 0.1d0 * trialHeight50m200(:)
1466 trialHeight5m50(:) = 0.1d0 * trialHeight5m50(:)
1467 trialHeight1m10(:) = 0.1d0 * trialHeight1m10(:)
1468
1469 write(*,*) 'bcs_getTrialPredictors: end'
1470
1471 contains
1472
1473 function logInterpHeight(columnTrlOnTrlLev, headerIndex, p) result(height)
1474 implicit none
1475
1476 ! Arguments:
1477 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
1478 integer, intent(in) :: headerIndex
1479 real(8), intent(in) :: p
1480 ! Result:
1481 real(8) :: height
1482
1483 ! Locals:
1484 integer :: jk, nlev, ik
1485 real(8) :: zpt, zpb, zwt, zwb
1486 real(8), pointer :: col_ptr(:)
1487
1488 ik = 1
1489 nlev = col_getNumLev(columnTrlOnTrlLev, 'TH')
1490 do jk = 2, nlev - 1
1491 zpt = col_getPressure(columnTrlOnTrlLev, jk, headerIndex, 'TH') * MPC_MBAR_PER_PA_R8
1492 if(p > zpt) ik = jk
1493 end do
1494 zpt = col_getPressure(columnTrlOnTrlLev, ik, headerIndex, 'TH') * MPC_MBAR_PER_PA_R8
1495 zpb = col_getPressure(columnTrlOnTrlLev, ik + 1, headerIndex, 'TH') * MPC_MBAR_PER_PA_R8
1496
1497 zwb = log(p/zpt) / log(zpb/zpt)
1498 zwt = 1.d0 - zwb
1499 col_ptr => col_getColumn(columnTrlOnTrlLev, headerIndex, 'Z_T')
1500
1501 height = zwb * col_ptr(ik+1) + zwt * col_ptr(ik)
1502
1503 end function logInterpHeight
1504
1505 end subroutine bcs_getTrialPredictors
1506
1507 !----------------------
1508 ! bcs_cvToCoeff
1509 !----------------------
1510 subroutine bcs_cvToCoeff(cv_bias)
1511 !
1512 !:Purpose: get coefficient increment from control vector
1513 !
1514 implicit none
1515
1516 ! Arguments:
1517 real(8), intent(in) :: cv_bias(:)
1518
1519 ! Locals:
1520 integer :: index_cv, iSensor, iChannel, iPredictor, iScan
1521 integer :: nsize, ierr
1522
1523 if (mmpi_myid == 0) then
1524 write(*,*) 'bcs_cvToCoeff: start'
1525 index_cv = 0
1526 ! initialize of coeffIncr
1527 do iSensor = 1, tvs_nSensors
1528 if (bias(iSensor)%numScan > 0) then
1529 do iChannel = 1, bias(iSensor)%numChannels
1530 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1531 bias(iSensor)%chans(iChannel)%coeffIncr(:) = 0.0d0
1532 bias(iSensor)%chans(iChannel)%coeffIncr_fov(:) = 0.0d0
1533 end if
1534 end do
1535 end if
1536 end do
1537
1538 do iSensor = 1, tvs_nSensors
1539 if (bias(iSensor)%numScan > 0) then
1540 do iChannel = 1, bias(iSensor)%numChannels
1541 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1542 do iPredictor = 1, bias(iSensor)%chans(iChannel)%numActivePredictors
1543 if (iPredictor == 1) then
1544 do iScan = 1, bias(iSensor)%numScan
1545 index_cv = index_cv + 1
1546 bias(iSensor)%chans(iChannel)%coeffIncr_fov(iScan) = bias(iSensor)%chans(iChannel)%stddev(iPredictor) * cv_bias(index_cv)
1547 end do
1548 else
1549 index_cv = index_cv + 1
1550 bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor) = bias(iSensor)%chans(iChannel)%stddev(iPredictor) * cv_bias(index_cv)
1551 end if
1552 end do !iPredictor
1553 end if ! isDynamic
1554 end do !iChannel
1555 end if
1556 end do !iSensor
1557
1558 end if
1559
1560 ! for constant part
1561 do iSensor = 1, tvs_nSensors
1562 if (bias(iSensor)%numScan > 0) then
1563 nsize = bias(iSensor)%numScan
1564 do iChannel = 1, bias(iSensor)%numChannels
1565 if (bias(iSensor)%chans(iChannel)%isDynamic) &
1566 call rpn_comm_bcast(bias(iSensor)%chans(iChannel)%coeffIncr_fov, nsize, "mpi_double_precision", 0, "GRID", ierr)
1567 end do
1568 end if
1569 end do
1570
1571 ! for predictor part
1572 do iSensor = 1, tvs_nSensors
1573 if (bias(iSensor)%numScan > 0) then
1574 do iChannel = 1, bias(iSensor)%numChannels
1575 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1576 nsize = bias(iSensor)%chans(iChannel)%numActivePredictors
1577 call rpn_comm_bcast(bias(iSensor)%chans(iChannel)%coeffIncr, nsize, "mpi_double_precision", 0, "GRID", ierr)
1578 end if
1579 end do
1580 end if
1581 end do
1582
1583 end subroutine bcs_cvToCoeff
1584
1585 !-----------------------------------
1586 ! bcs_getPredictors
1587 !----------------------------------
1588 subroutine bcs_getPredictors(predictor, headerIndex, obsIndex, chanindx, obsSpaceData)
1589 !
1590 !:Purpose: get predictors
1591 !
1592 implicit none
1593
1594 ! Arguments:
1595 real(8), intent(out) :: predictor(NumPredictors)
1596 integer, intent(in) :: headerIndex
1597 integer, intent(in) :: obsIndex
1598 integer, intent(in) :: chanindx
1599 type(struct_obs), intent(inout) :: obsSpaceData
1600
1601 ! Locals:
1602 integer :: iSensor, iPredictor, jPredictor
1603 real(8) :: zenithAngle
1604
1605 predictor(:) = 0.0d0
1606
1607 do iPredictor = 1, NumPredictors
1608
1609 if (iPredictor == 1) then
1610 ! constant
1611 predictor(iPredictor) = 1.0d0
1612 else if (iPredictor == 2) then
1613 ! Height300-Height1000 (dam) /1000 T1
1614 predictor(iPredictor) = trialHeight300m1000(obsIndex) / 1000.0d0
1615 else if (iPredictor == 3) then
1616 ! Height50-Height200 (dam) /1000 T2
1617 predictor(iPredictor) = trialHeight50m200(obsIndex) / 1000.0d0
1618 else if (iPredictor == 4) then
1619 ! Height5-Height50 (dam) /1000 T3
1620 predictor(iPredictor) = trialHeight5m50(obsIndex) / 1000.0d0
1621 else if (iPredictor == 5) then
1622 ! Height1-Height10 (dam) /1000 T4
1623 predictor(iPredictor) = trialHeight1m10(obsIndex) / 1000.0d0
1624 else if (iPredictor == 6) then
1625 ! SV secant of satellite zenith angle minus one
1626 zenithAngle = obs_headElem_r(obsSpaceData, OBS_SZA, headerIndex)
1627 if (zenithAngle < 75.) predictor(iPredictor) = (1.d0 / cos(zenithAngle * MPC_RADIANS_PER_DEGREE_R8)) - 1.d0
1628 else if (iPredictor == 7) then
1629 ! skin temperature (C) /10
1630 predictor(iPredictor) = trialTG(obsIndex)
1631 end if
1632
1633 end do
1634
1635 iSensor = tvs_lsensor(tvs_tovsIndex(headerIndex))
1636 do iPredictor = 1, bias(iSensor)%chans(chanIndx)%numActivePredictors
1637 jPredictor = bias(iSensor)%chans(chanIndx)%predictorIndex(iPredictor)
1638 predictor(jPredictor) = predictor(jPredictor) - bias(iSensor)%chans(chanindx)%coeff_offset(iPredictor)
1639 end do
1640
1641 end subroutine bcs_getPredictors
1642
1643 !---------------------------------------------
1644 ! bcs_calcBias_ad
1645 !---------------------------------------------
1646 subroutine bcs_calcBias_ad(cv_out, obsColumnIndex, obsSpaceData)
1647 !
1648 !:Purpose: bias computation adjoint (for varBC)
1649 !
1650 implicit none
1651
1652 ! Arguments:
1653 real(8), intent(in) :: cv_out(:)
1654 integer, intent(in) :: obsColumnIndex
1655 type(struct_obs), intent(inout) :: obsSpaceData
1656
1657 ! Locals:
1658 integer :: headerIndex, bodyIndex, iobs, idatyp
1659 integer :: iSensor, iChannel, iPredictor, chanIndx
1660 integer :: iScan, iFOV, jPred
1661 real(8) :: predictor(NumPredictors)
1662 real(8), pointer :: cv_bias(:)
1663 real(8), target :: dummy4Pointer(1)
1664 real(8) :: biasCor
1665
1666 if (.not. biasActive) return
1667
1668 if (mmpi_myid == 0) write(*,*) 'bcs_calcBias_ad: start'
1669
1670 nullify(cv_bias)
1671 if (mmpi_myid == 0) then
1672 if (cvm_subVectorExists('BIAS')) then
1673 cv_bias => cvm_getSubVector(cv_out, 'BIAS')
1674 else
1675 write(*,*) 'bcs_calcBias_ad: control vector does not include bias coefficients'
1676 return
1677 end if
1678 else
1679 cv_bias => dummy4Pointer
1680 end if
1681
1682 ! adjoint of applying bias increment to specified obs column
1683 do iSensor = 1, tvs_nSensors
1684 if (bias(iSensor)%numScan > 0) then
1685 do iChannel = 1, bias(iSensor)%numChannels
1686 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1687 bias(iSensor)%chans(iChannel)%coeffIncr(:) = 0.0d0
1688 bias(iSensor)%chans(iChannel)%coeffIncr_fov(:) = 0.0d0
1689 end if
1690 end do
1691 end if
1692 end do
1693
1694 iobs = 0
1695 call obs_set_current_header_list(obsSpaceData, 'TO')
1696 HEADER: do
1697 headerIndex = obs_getHeaderIndex(obsSpaceData)
1698 if (headerIndex < 0) exit HEADER
1699 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
1700 if (.not. tvs_isIdBurpTovs(idatyp)) then
1701 write(*,*) 'bcs_calcBias_ad: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
1702 cycle HEADER
1703 end if
1704 iobs = iobs + 1
1705 if (tvs_tovsIndex(headerIndex) < 0) cycle HEADER
1706
1707 iSensor = tvs_lsensor(tvs_tovsIndex(headerIndex))
1708
1709 call obs_set_current_body_list(obsSpaceData, headerIndex)
1710 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
1711
1712 BODY: do
1713 bodyIndex = obs_getBodyIndex(obsSpaceData)
1714 if (bodyIndex < 0) exit BODY
1715
1716 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
1717
1718 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
1719
1720 if (chanindx > 0) then
1721 if (bias(iSensor)%chans(chanIndx)%isDynamic) then
1722 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
1723 biasCor = obs_bodyElem_r(obsSpaceData, obsColumnIndex, bodyIndex)
1724 do iPredictor = 1, bias(iSensor)%chans(chanIndx)%numActivePredictors
1725 jPred = bias(iSensor)%chans(chanIndx)%PredictorIndex(iPredictor)
1726 if (jPred == 1) then
1727 if (bias(iSensor)%numScan > 1) then
1728 iScan = iFov
1729 else
1730 iScan = 1
1731 end if
1732 bias(iSensor)%chans(chanIndx)%coeffIncr_fov(iScan) = bias(iSensor)%chans(chanIndx)%coeffIncr_fov(iScan) &
1733 + predictor(jPred) * biasCor
1734 else
1735 bias(iSensor)%chans(chanIndx)%coeffIncr(iPredictor) = bias(iSensor)%chans(chanIndx)%coeffIncr(iPredictor) &
1736 + predictor(jPred) * biasCor
1737 end if
1738 end do !iPredictor
1739 end if
1740 end if
1741
1742 end do BODY
1743
1744 end do HEADER
1745
1746 ! put the coefficients into the control vector
1747 call bcs_cvToCoeff_ad(cv_bias)
1748
1749 if (mmpi_myid == 0) then
1750 write(*,*) 'bcs_calcBias_ad: maxval(cv_bias) = ', maxval(cv_bias(:))
1751 end if
1752
1753 end subroutine bcs_calcBias_ad
1754
1755 !----------------------------------------------------
1756 ! bcs_cvToCoeff_ad
1757 !----------------------------------------------------
1758 subroutine bcs_cvToCoeff_ad(cv_bias)
1759 !
1760 !:Purpose: adjoint of control vector to coeff transfer (for varBC)
1761 !
1762 implicit none
1763
1764 ! Arguments:
1765 real(8), intent(inout) :: cv_bias(:)
1766
1767 ! Locals:
1768 integer :: index_cv, iSensor, iChannel, iPredictor, iScan
1769 integer :: nChan, nScan
1770 integer :: nsize, iChan
1771 real(8), allocatable :: temp_coeffIncr(:), temp_coeffIncr_fov(:)
1772
1773 write(*,*) "bcs_cvToCoeff_ad: start"
1774
1775 do iSensor = 1, tvs_nSensors
1776 if (bias(iSensor)%numScan > 0) then
1777 nChan = bias(iSensor)%numChannels
1778 do ichan = 1, nChan
1779 if (bias(iSensor)%chans(ichan)%isDynamic) then
1780 nSize = bias(iSensor)%chans(iChan)%numActivePredictors
1781 allocate(temp_coeffIncr(nSize))
1782 temp_coeffIncr(:) = 0.0d0
1783 call mmpi_reduce_sumR8_1d( bias(iSensor)%chans(ichan)%coeffIncr(:), temp_coeffIncr, 0, "GRID" )
1784 bias(iSensor)%chans(ichan)%coeffIncr(:) = temp_coeffIncr(:)
1785 deallocate(temp_coeffIncr)
1786 end if
1787 end do
1788 end if
1789 end do
1790
1791 do iSensor = 1, tvs_nSensors
1792 if (bias(iSensor)%numScan > 0) then
1793 nChan = bias(iSensor)%numChannels
1794 nScan = bias(iSensor)%numScan
1795 nsize = nChan * nScan
1796 if (nsize > 0) then
1797 allocate(temp_coeffIncr_fov(1:nScan))
1798 do ichan = 1, nChan
1799 if (bias(iSensor)%chans(ichan)%isDynamic) then
1800 temp_coeffIncr_fov(:) = 0.0d0
1801 call mmpi_reduce_sumR8_1d( bias(iSensor)%chans(ichan)%coeffIncr_fov, temp_coeffIncr_fov, 0, "GRID" )
1802 bias(iSensor)%chans(iChan)%coeffIncr_fov(:) = temp_coeffIncr_fov(:)
1803 end if
1804 end do
1805 deallocate(temp_coeffIncr_fov)
1806 end if
1807 end if
1808 end do
1809
1810 if (mmpi_myid == 0) then
1811 cv_bias(:) = 0.d0
1812 index_cv = 0
1813 do iSensor = 1, tvs_nSensors
1814 if (bias(iSensor)%numScan > 0) then
1815 do iChannel = 1, bias(iSensor)%numChannels
1816 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1817 do iPredictor = 1, bias(iSensor)%chans(iChannel)%numActivePredictors
1818 if (iPredictor == 1) then
1819 do iScan = 1, bias(iSensor)%numScan
1820 index_cv = index_cv + 1
1821 cv_bias(index_cv) = bias(iSensor)%chans(iChannel)%stddev(iPredictor) * bias(iSensor)%chans(iChannel)%coeffIncr_fov(iScan)
1822 end do
1823 else
1824 index_cv = index_cv + 1
1825 cv_bias(index_cv) = bias(iSensor)%chans(iChannel)%stddev(iPredictor) * bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor)
1826 end if
1827 end do
1828 end if
1829 end do
1830 end if
1831 end do
1832 end if
1833
1834 end subroutine bcs_cvToCoeff_ad
1835
1836 !-----------------------------------------
1837 ! bcs_writeBias
1838 !-----------------------------------------
1839 subroutine bcs_writeBias(cv_in_opt)
1840 !
1841 !:Purpose: to write bias increments and coefficients (varBC)
1842 !
1843 implicit none
1844
1845 ! Arguments:
1846 real(8), optional, intent(in) :: cv_in_opt(:)
1847
1848 ! Locals:
1849 integer :: iSensor, iChannel, iPredictor, iScan
1850 integer :: jSensor, iChannel2
1851 integer :: nulfile_inc, nulfile_fov, ierr
1852 real(8), pointer :: cv_bias(:)
1853 real(8), target :: dummy4Pointer(1)
1854 character(len=80) :: BgFileName
1855 !for background coeff and write out
1856 integer :: iInstr
1857 integer :: numCoefFile, jCoef, kCoef
1858 character(len=10) :: coefInstrName(tvs_nSensors), temp_instrName
1859 character(len=25) :: filecoeff
1860 logical :: coeffExists
1861 ! these variables are not used but need to be present to satisfy bcs_updateCoeff interface
1862 ! some bcs_updateCoeff arguments could be made optional (todo)
1863 integer :: chans(tvs_nSensors, tvs_maxChannelNumber), nsat, nfov
1864 integer :: nchan(tvs_nSensors)
1865 character(len=10) :: sats(tvs_nsensors) ! satellite names
1866 character(len=7) :: cinstrum ! string: instrument (e.g. AMSUB)
1867
1868 if (.not. biasActive) return
1869
1870 if (present(cv_in_opt)) then
1871 nullify(cv_bias)
1872 if (mmpi_myid == 0) then
1873 if (cvm_subVectorExists('BIAS')) then
1874 cv_bias => cvm_getSubVector(cv_in_opt, 'BIAS')
1875 write(*,*) 'bcs_writeBias: maxval(cv_bias) = ', maxval(cv_bias(:))
1876 else
1877 write(*,*) 'bcs_writeBias: control vector does not include bias coefficients'
1878 return
1879 end if
1880 else
1881 cv_bias => dummy4Pointer
1882 end if
1883 call bcs_cvToCoeff(cv_bias)
1884 end if
1885
1886 ! apply transformation to account for predictor offset
1887
1888 do iSensor = 1, tvs_nSensors
1889 if (bias(iSensor)%numScan > 0) then
1890 do iChannel = 1, bias(iSensor)%numChannels
1891 do iPredictor = 2, bias(iSensor)%chans(iChannel)%numActivePredictors
1892 if (mimicSatbcor) then
1893 bias(iSensor)%chans(iChannel)%coeffIncr(1) = bias(iSensor)%chans(iChannel)%coeffIncr(1) - &
1894 bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor) * bias(iSensor)%chans(iChannel)%coeff_offset(iPredictor)
1895 else
1896 do iScan = 1, bias(iSensor)%numScan
1897 bias(iSensor)%chans(iChannel)%coeffIncr_fov(iScan) = bias(iSensor)%chans(iChannel)%coeffIncr_fov(iScan) - &
1898 bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor) * bias(iSensor)%chans(iChannel)%coeff_offset(iPredictor)
1899 end do
1900 end if
1901 end do
1902 if (bias(iSensor)%chans(iChannel)%numActivePredictors > 0 .and. mmpi_myId ==0 .and. (.not. doRegression)) &
1903 write(*,*) "bcs_writeBias: bias(iSensor)%chans(iChannel)%coeffIncr(:) = ", bias(iSensor)%chans(iChannel)%coeffIncr(:)
1904 end do
1905 end if
1906 end do
1907
1908 if (doRegression) then
1909 call bcs_writeCoeff()
1910 return
1911 end if
1912
1913 if (mmpi_myId == 0) then
1914
1915 ! write out bias coefficient increments in ascii file
1916 nulfile_inc = 0
1917 ierr = fnom(nulfile_inc, './satbias_increment.dat', 'FTN+FMT', 0)
1918
1919 do iSensor = 1, tvs_nSensors
1920 write(nulfile_inc,'(/,1X,"Sensor Index=",I3,", Satellite Name=",A15,", Instrument Name=",A15)') &
1921 iSensor, tvs_satelliteName(iSensor), tvs_instrumentName(iSensor)
1922 if (bias(iSensor)%numScan > 0) then
1923 do iChannel = 1, bias(iSensor)%numChannels
1924 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1925 iChannel2 = bias(iSensor)%chans(iChannel)%channelNum
1926 if (sum(bias(iSensor)%chans(iChannel)%coeffIncr(:)) /= 0.0d0) &
1927 write(nulfile_inc,'(3X,"Channel number=",I4)') iChannel2
1928 do iPredictor = 2, bias(iSensor)%chans(iChannel)%numActivePredictors
1929 if (bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor) /= 0.0d0) &
1930 write(nulfile_inc,'(5X,"Predictor number=",I4,", Coefficient=",e12.4)') &
1931 iPredictor, bias(iSensor)%chans(iChannel)%coeffIncr(iPredictor)
1932 end do
1933 end if
1934 end do
1935 end if
1936 end do
1937
1938 ierr = fclos(nulfile_inc)
1939
1940 ! write out fovbias coefficient increments in ascii file
1941 nulfile_fov = 0
1942 ierr = fnom(nulfile_fov, './fovbias_incre.dat', 'FTN+FMT', 0)
1943 do iSensor = 1, tvs_nSensors
1944 write(nulfile_fov,'(/,1X,"Sensor Index=",I3,", Satellite Name=",A15,", Instrument Name=",A15)') &
1945 iSensor, tvs_satelliteName(iSensor), tvs_instrumentName(iSensor)
1946 if (bias(iSensor)%numScan > 0) then
1947 do iChannel = 1, bias(iSensor)%numChannels
1948 if (bias(iSensor)%chans(iChannel)%isDynamic) then
1949 iChannel2 = bias(iSensor)%chans(iChannel)%channelNum
1950 if (sum(bias(iSensor)%chans(iChannel)%coeffIncr_fov(:)) /= 0.0d0) then
1951 write(nulfile_fov,'(3X,"Channel number=",I4)') iChannel2
1952 write(nulfile_fov,*) bias(iSensor)%chans(iChannel)%coeffIncr_fov(:)
1953 end if
1954 end if
1955 end do
1956 end if
1957 end do
1958 ierr = fclos(nulfile_fov)
1959
1960 end if
1961
1962 ! Find the background coeff_file number and name
1963 do iSensor = 1, tvs_nSensors
1964 numCoefFile = 0
1965 jCoef = 0
1966 do jSensor = 1, tvs_nSensors
1967 temp_instrName = InstrNametoCoeffFileName(tvs_instrumentName(jSensor))
1968 filecoeff = 'coeff_file_' // trim(temp_instrName) // ''
1969 inquire(file=trim(filecoeff), exist=coeffExists)
1970
1971 if (coeffExists) then
1972 numCoefFile = numCoefFile + 1
1973 jCoef = jCoef + 1
1974 coefInstrName(jCoef) = temp_instrName
1975 end if
1976 if (jSensor > 1) then
1977 do kCoef = 1, jCoef - 1
1978 if (temp_instrName == coefInstrName(kCoef)) then
1979 numCoefFile = numCoefFile - 1
1980 jCoef = jCoef - 1
1981 end if
1982 end do
1983 end if
1984 end do
1985 end do
1986
1987 ! update coeff_file_instrument and write out
1988 do iInstr=1, numCoefFile
1989 BgFileName = './coeff_file_' // coefInstrName(iInstr)
1990 call bcs_updateCoeff(tvs_nSensors, NumPredictors, BgFileName, sats, chans, nsat, nchan, nfov, cinstrum)
1991 end do
1992
1993 end subroutine bcs_writeBias
1994
1995 !-----------------------------------------
1996 ! bcs_updateCoeff
1997 !-----------------------------------------
1998 subroutine bcs_updateCoeff(maxsat, maxpred, coeff_file, sats, chans, nsat, nchan, nfov, cinstrum, updateCoeff_opt)
1999 !
2000 !:Purpose: to read, and optionaly update and write out, the coeff files (varBC).
2001 !
2002 implicit none
2003
2004 ! Arguments:
2005 integer, intent(in) :: maxsat, maxpred
2006 character(len=*), intent(in) :: coeff_file
2007 logical, optional, intent(in) :: updateCoeff_opt
2008 integer, intent(out) :: chans(maxsat,tvs_maxChannelNumber) ! channel numbers
2009 integer, intent(out) :: nsat
2010 integer, intent(out) :: nfov
2011 integer, intent(out) :: nchan(maxsat) ! number of channels
2012 character(len=10), intent(out) :: sats(maxsat) ! Satellite names
2013 character(len=*), intent(out) :: cinstrum ! instrument (e.g. AMSUB)
2014
2015 ! Locals:
2016 real(8) :: fovbias(maxsat,tvs_maxChannelNumber,maxfov)
2017 real(8) :: coeff(maxsat,tvs_maxChannelNumber,maxpred)
2018 character(len=2) :: ptypes(maxsat,tvs_maxChannelNumber,maxpred)
2019 integer :: npred(maxsat,tvs_maxChannelNumber) ! number of predictors
2020 integer :: ndata(maxsat,tvs_maxChannelNumber)
2021 ! LOCAL for reading background coeff file
2022 integer :: iSat, jChan, kPred, kFov
2023 logical :: verbose
2024 ! update coeff files
2025 real :: fovbias_an(maxsat,tvs_maxChannelNumber,maxfov)
2026 real :: coeff_an(maxsat,tvs_maxChannelNumber,maxpred)
2027 integer :: iSensor, jChannel, iFov, iPred, totPred
2028 character(len=10) :: tmp_SatName, tmp_InstName
2029 ! write out files
2030 integer :: iuncoef2, ierr, numPred
2031 character(len=80):: filename2
2032 logical :: updateCoeff_opt2
2033 ! sats(nsat) = satellite names
2034 ! chans(nsat, nchan(i)) = channel numbers of each channel of each satellite i
2035 ! npred(nsat, nchan(i)) = number of predictors for each channel of each satellite i
2036 ! fovbias(i, j, k) = bias for satellite i, channel j, FOV k k=1,nfov
2037 ! if FOV not considered for instrument, nfov = 1 and fovbias is global bias for channel
2038 ! coeff(i, j, 1) = regression constant
2039 ! coeff(i, j, 2), ..., coeff(i, j, npred(i, j)) = predictor coefficients
2040 ! nsat, nchan, nfov, cinstrum (output) are determined from file
2041 ! if returned nsat = 0, coeff_file was empty
2042 ! maxpred (input) is max number of predictors
2043 ! maxsat (input) is max number of satellites
2044
2045 ! There are three parts in this subroutine, read, update and write out the coeff files
2046 !
2047 !- 1. read in the background coeff files, this program is read_coeff from genbiascorr
2048 !
2049 if (present(updateCoeff_opt)) then
2050 updateCoeff_opt2 = updateCoeff_opt
2051 else
2052 updateCoeff_opt2 = .true.
2053 end if
2054
2055 verbose = .false.
2056
2057 call read_coeff(sats, chans, fovbias, coeff, nsat, nchan, nfov, &
2058 npred, cinstrum, coeff_file, ptypes, ndata)
2059
2060 ! Transfer of coefficients read from file to the bias structure
2061 satloop :do iSat = 1, nsat !backgroud sat
2062 instloop:do iSensor = 1, tvs_nSensors
2063 ! for Satellite Name
2064 tmp_SatName = SatNameinCoeffFile(tvs_satelliteName(iSensor))
2065 ! for Instrument Name
2066 tmp_InstName = InstrNameinCoeffFile(tvs_instrumentName(iSensor))
2067
2068 if (trim(tmp_SatName) /= trim(sats(iSat)) .or. trim(tmp_InstName) /= trim(cinstrum)) cycle instloop
2069 write(*,*) "bcs_updateCoeff: " // tmp_SatName // " " // tmp_InstName
2070
2071 if (.not. allocated(bias(iSensor)%chans)) cycle instloop
2072
2073 chan1loop:do jChan = 1, nchan(iSat)
2074 chan2loop:do jChannel = 1, bias(iSensor)%numChannels
2075
2076 if (chans(iSat, jChan) /= bias(iSensor)%chans(jChannel)%channelNum) cycle chan2loop
2077
2078 ! part 1 for coeffIncr
2079 do iFov = 1, nfov
2080 bias(iSensor)%chans(jchannel)%coeff_fov(iFov) = fovbias(iSat, jChan, iFov)
2081 end do ! iFov
2082
2083 ! part 2 for coeffIncr_fov
2084 totPred = bias(iSensor)%chans(jchannel)%NumActivePredictors
2085 do iPred = 1, totPred
2086 bias(iSensor)%chans(jchannel)%coeff(iPred) = coeff(iSat, jChan, iPred)
2087 end do ! iPred
2088
2089 end do chan2loop ! jChannel
2090 end do chan1loop !jChan
2091
2092 end do instloop
2093 end do satloop
2094
2095 if (.not. updateCoeff_opt2) return
2096
2097 !
2098 !- 2.update coeff and fovbias
2099 !
2100 coeff_an(:,:,:) = coeff(:,:,:)
2101 fovbias_an(:,:,:) = fovbias(:,:,:)
2102
2103 do iSat = 1, nsat !backgroud sat
2104 do iSensor = 1, tvs_nSensors
2105 ! for Satellite Name
2106 tmp_SatName = SatNameinCoeffFile(tvs_satelliteName(iSensor))
2107 ! for Instrument Name
2108 tmp_InstName = InstrNameinCoeffFile(tvs_instrumentName(iSensor))
2109 if (trim(tmp_SatName) /= trim(sats(iSat)) .or. trim(tmp_InstName) /= trim(cinstrum)) cycle
2110 do jChan = 1, nchan(iSat)
2111 do jChannel = 1, bias(iSensor)%numChannels
2112
2113 if (chans(iSat, jChan) /= bias(iSensor)%chans(jChannel)%channelNum) cycle
2114
2115 ! part 1 for coeffIncr
2116 do iFov = 1, nfov
2117 fovbias_an(iSat, jChan, iFov) = fovbias(iSat, jChan, iFov) + bias(iSensor)%chans(jchannel)%coeffIncr_fov(iFov)
2118 end do ! iFov
2119
2120 ! part 2 for coeffIncr_fov
2121 totPred = bias(iSensor)%chans(jchannel)%NumActivePredictors
2122 do iPred = 1, totPred
2123 coeff_an(iSat, jChan, iPred) = coeff(iSat, jChan, iPred) + bias(iSensor)%chans(jchannel)%coeffIncr(iPred)
2124 end do ! iPred
2125
2126 end do ! jChannel
2127 end do !jChan
2128 end do !iSensor
2129 end do ! iSat
2130
2131 !
2132 !- 3. Write out updated_coeff
2133 !
2134
2135 if (mmpi_myId == 0) then
2136
2137 iuncoef2 = 0
2138 filename2 = './anlcoeffs_' // cinstrum
2139 ierr = fnom(iuncoef2, filename2, 'FTN+FMT', 0)
2140
2141 write(*,*) 'bcs_updateCoeff: write in bcs_updateCoeff'
2142
2143 do iSat = 1, nsat
2144 do jChan = 1, nchan(iSat)
2145 numPred = npred(iSat, jChan)
2146 if (sum(abs(coeff_an(iSat, jchan, 1:numpred+1))) /= 0.d0 .and. sum(abs(fovbias_an(iSat, jChan, 1:nfov))) /= 0.d0) then
2147 write(iuncoef2,'(A52,A8,1X,A7,1X,I6,1X,I8,1X,I2,1X,I3)') &
2148 'SATELLITE, INSTRUMENT, CHANNEL, NOBS, NPRED, NSCAN: ', sats(iSat), cinstrum, chans(iSat,jChan), ndata(isat,jchan), numPred, nfov
2149 write(iuncoef2,'(A7,6(1X,A2))') 'PTYPES:', (ptypes(iSat, jChan, kPred), kPred = 1, numPred)
2150 write(iuncoef2,'(120(1x,ES17.10))') (fovbias_an(iSat, jChan, kFov), kFov = 1, nfov)
2151 write(iuncoef2,*) (coeff_an(iSat, jChan, kPred), kPred = 1, numPred + 1)
2152 end if
2153 end do
2154 end do
2155
2156 ierr = fclos(iuncoef2)
2157
2158 write(*,*) 'bcs_updateCoeff: finish writing coeffient file', filename2
2159
2160 end if
2161
2162 end subroutine bcs_updateCoeff
2163
2164 !-----------------------------------------
2165 ! bcs_writeCoeff
2166 !-----------------------------------------
2167 subroutine bcs_writeCoeff()
2168 !
2169 !:Purpose: write out the coeff files (regression case).
2170 !
2171 implicit none
2172
2173 ! Locals:
2174 integer :: iuncoef, numPred, ierr
2175 character(len=80) :: filename
2176 character(len=80) :: instrName, satNamecoeff
2177 integer :: sensorIndex, nchans, nscan, nfov, kpred, kFov, jChan
2178
2179 if (mmpi_myId == 0) then
2180
2181 SENSORS:do sensorIndex = 1, tvs_nsensors
2182
2183 if (.not. tvs_isReallyPresentMpiGLobal(sensorIndex)) cycle SENSORS
2184
2185 write(*,*) "bcs_writeCoeff: sensorIndex ", sensorIndex
2186
2187 nchans = bias(sensorIndex)%numChannels
2188 nscan = bias(sensorIndex)%numscan
2189
2190 instrName = InstrNameinCoeffFile(tvs_instrumentName(sensorIndex))
2191 satNamecoeff = SatNameinCoeffFile(tvs_satelliteName(sensorIndex))
2192
2193 filename = './anlcoeffs_' // trim(instrName)
2194 call utl_open_asciifile(filename, iuncoef)
2195 nfov = bias(sensorIndex)%numScan
2196 do jChan = 1, nchans
2197 if (bias(sensorIndex)%chans(jChan)%coeff_nobs > 0) then
2198 numPred = bias(sensorIndex)%chans(jChan)%numActivePredictors
2199
2200 write(iuncoef,'(A52,A8,1X,A7,1X,I6,1X,I8,1X,I2,1X,I3)') 'SATELLITE, INSTRUMENT, CHANNEL, NOBS, NPRED, NSCAN: ', &
2201 satNameCoeff, instrName, bias(sensorIndex)%chans(jChan)%channelNum, bias(sensorIndex)%chans(jChan)%coeff_nobs, numPred - 1, nfov
2202 write(iuncoef,'(A7,6(1X,A2))') 'PTYPES:', (predtab(bias(sensorIndex)%chans(jChan)%predictorIndex(kPred)), kPred = 2, numPred)
2203 write(iuncoef,'(120(1x,ES17.10))') (bias(sensorIndex)%chans(jChan)%coeff_fov(kFov), kFov = 1, nfov)
2204 write(iuncoef,'(12(1x,ES17.10))') (bias(sensorIndex)%chans(jChan)%coeff(kPred), kPred = 1, numPred)
2205 end if
2206 end do
2207
2208 ierr = fclos(iuncoef)
2209
2210 if (outCoeffCov) then
2211 filename = './anlcoeffsCov_' // trim(instrName)
2212 call utl_open_asciifile(filename, iuncoef)
2213 do jChan = 1, nchans
2214 if (bias(sensorIndex)%chans(jChan)%coeff_nobs > 0) then
2215 numPred = bias(sensorIndex)%chans(jChan)%numActivePredictors
2216
2217 write(iuncoef,'(A38,A8,1X,A7,1X,I6,1X,I2)') 'SATELLITE, INSTRUMENT, CHANNEL, NPRED: ', &
2218 satNameCoeff, instrName, bias(sensorIndex)%chans(jChan)%channelNum, numPred
2219 do kpred =1, numPred
2220 write(iuncoef,'(10e14.6)') bias(sensorIndex)%chans(jChan)%coeffCov(kpred, :)
2221 end do
2222 end if
2223 end do
2224 ierr = fclos(iuncoef)
2225 end if
2226
2227 end do SENSORS
2228
2229 end if
2230
2231 end subroutine bcs_writeCoeff
2232
2233 !-----------------------------------------
2234 ! bcs_removeBiasCorrection
2235 !-----------------------------------------
2236 subroutine bcs_removeBiasCorrection(obsSpaceData, family_opt)
2237 !
2238 !:Purpose: to remove bias correction from OBS_VAR
2239 ! After the call OBS_VAR contains the uncorrected
2240 ! observation and OBS_BCOR is set to zero
2241 !
2242 implicit none
2243
2244 ! Arguments:
2245 type(struct_obs), intent(inout) :: obsSpaceData
2246 character(len=2), optional, intent(in) :: family_opt
2247
2248 ! Locals:
2249 integer :: nbcor
2250 integer :: bodyIndex
2251 real(8) :: biascor, Obs
2252
2253 if (.not. removeBiasCorrection) return
2254
2255 if (mmpi_myid == 0) write(*,*) 'bcs_removeBiasCorrection: start'
2256
2257 nbcor = 0
2258 call obs_set_current_body_list(obsSpaceData, family_opt)
2259
2260 BODY: do
2261 bodyIndex = obs_getBodyIndex(obsSpaceData)
2262 if (bodyIndex < 0) exit BODY
2263 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
2264 biasCor = obs_bodyElem_r(obsSpaceData, OBS_BCOR, bodyIndex)
2265 Obs = obs_bodyElem_r(obsSpaceData, OBS_VAR, bodyIndex)
2266 if (biasCor /= MPC_missingValue_R8 .and. Obs /= MPC_missingValue_R8) then
2267 call obs_bodySet_r(obsSpaceData, OBS_VAR, bodyIndex, real(Obs - biasCor, pre_obsReal))
2268 call obs_bodySet_r(obsSpaceData, OBS_BCOR, bodyIndex, real(0.d0, pre_obsReal))
2269 nbcor = nbcor + 1
2270 end if
2271 end do BODY
2272
2273 if (mmpi_myid == 0) then
2274 write(*,*) 'bcs_removeBiasCorrection: removed bias correction for ', nbcor, ' observations'
2275 write(*,*) 'bcs_removeBiasCorrection exiting'
2276 end if
2277
2278 end subroutine bcs_removeBiasCorrection
2279
2280 !-----------------------------------------
2281 ! bcs_filterObs
2282 !-----------------------------------------
2283 subroutine bcs_filterObs(obsSpaceData)
2284 !
2285 !:Purpose: to filter radiance observations to include into
2286 ! bias correction offline computation
2287 ! (same rules as in bgck.gen_table)
2288 !
2289 implicit none
2290
2291 ! Arguments:
2292 type(struct_obs), intent(inout) :: obsSpaceData
2293
2294 ! Locals:
2295 integer :: bodyIndex, headerIndex, instrumentIndex, sensorIndex
2296 integer, allocatable :: instrumentList(:)
2297 integer :: assim, flag, codtyp, channelNumber
2298 integer :: isatBufr, instBufr, iplatform, isat, inst, idsat, chanIndx
2299 logical :: lHyperIr, lGeo, lSsmis, lTovs
2300 logical :: condition, condition1, condition2, channelIsAllsky
2301 logical :: channelIsPassive
2302 character(len=10) :: instrName
2303
2304 if (.not. filterObs) return
2305
2306 if (mmpi_myid == 0) write(*,*) 'bcs_filterObs: start'
2307
2308 allocate(instrumentList(tvs_nsensors))
2309 instrumentList(:) = -1
2310 do sensorIndex = 1, tvs_nsensors
2311 instrName = InstrNameinCoeffFile(tvs_instrumentName(sensorIndex))
2312 do instrumentIndex = 1, maxNumInst
2313 if (trim(instrName) == trim(cinst(instrumentIndex))) then
2314 instrumentList(sensorIndex) = instrumentIndex
2315 end if
2316 end do
2317 if (instrumentList(sensorIndex) == -1) then
2318 call utl_abort('bcs_filterObs: Instrument ' // trim(instrName) // &
2319 'missing in CINST table fron NAMBIASSAT namelist section')
2320 end if
2321 end do
2322
2323 call obs_set_current_header_list(obsSpaceData, 'TO')
2324 HEADER: do
2325 headerIndex = obs_getHeaderIndex(obsSpaceData)
2326 if (headerIndex < 0) exit HEADER
2327
2328 codtyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
2329
2330 lHyperIr = .false.
2331 lGeo = .false.
2332 lSsmis = .false.
2333 lTovs = .false.
2334
2335 select case (codtyp_get_name(codtyp))
2336 case("ssmis")
2337 lSsmis = .true.
2338 case("csr")
2339 lGeo = .true.
2340 case("airs","iasi","cris","crisfsr")
2341 lHyperIr = .true.
2342 case default
2343 lTovs = .true.
2344 end select
2345
2346 isatBufr = obs_headElem_i(obsSpaceData, OBS_SAT, headerIndex) !BUFR element 1007
2347 instBufr = obs_headElem_i(obsSpaceData, OBS_INS, headerIndex) !BUFR element 2019
2348
2349 call tvs_mapSat(isatBufr, iplatform, isat)
2350 call tvs_mapInstrum(instBufr, inst)
2351
2352 idsat = -1
2353 do sensorIndex = 1, tvs_nsensors
2354 if (tvs_platforms(sensorIndex) == iplatform .and. &
2355 tvs_satellites(sensorIndex) == isat .and. &
2356 tvs_instruments(sensorIndex) == inst) then
2357 idsat = sensorIndex
2358 exit
2359 end if
2360 end do
2361 if (idsat == -1) cycle HEADER
2362
2363 call obs_set_current_body_list(obsSpaceData, headerIndex)
2364
2365 BODY: do
2366 bodyIndex = obs_getBodyIndex(obsSpaceData)
2367 if (bodyIndex < 0) exit BODY
2368
2369 ! determine if instrument/channel function in all-sky mode
2370 channelNumber = nint(obs_bodyElem_r(obsSpaceData, OBS_PPP, bodyIndex))
2371 channelIsAllsky = .false.
2372 if ((tvs_isInstrumUsingCLW(tvs_instruments(idsat)) .or. &
2373 tvs_isInstrumUsingHydrometeors(tvs_instruments(idsat))) .and. &
2374 oer_useStateDepSigmaObs(channelNumber, idsat)) then
2375 channelIsAllsky = .true.
2376 end if
2377 channelIsPassive = .false.
2378 if (passiveChannelNumber(instrumentList(idsat)) > 0) then
2379 channelIsPassive = (utl_findloc(passiveChannelList(instrumentList(idsat),1:passiveChannelNumber(instrumentList(idsat))), channelNumber) > 0)
2380 end if
2381 assim = obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex)
2382 if (assim == obs_notAssimilated) then
2383 call bcs_getChannelIndex(obsSpaceData, idsat, chanIndx, bodyIndex)
2384 if (chanIndx > 0) then
2385 flag = obs_bodyElem_i(obsSpaceData, OBS_FLG, bodyIndex)
2386
2387 if (lSsmis) then ! SSM/I and SSMIS
2388 ! Here "good" means data that are not rejected by first QC program satqc_ssmi(s) (bit 7 ON).
2389 ! Bit 11 is ON for data that are unselected by UTIL or for uncorrected data (or both).
2390 ! Data rejected by first QC program satqc_ssmi(s) have bit 7 switched ON only (in addition to bit 9) as
2391 ! rogue/topo checks are skipped. So if bit 16 (rogue) is ON, bit 7 must be off.
2392 if (.not. offlineMode .and. .not. channelIsPassive) then
2393 if (allModeSsmis) then
2394 ! FLAG test: all good data (corrected/selected or not) that have passed all QC (bit 9 OFF)
2395 condition1 = .not. btest(flag, 9) !' AND (FLAG & 512 = 0)'
2396 ! FLAG test: uncorrected good data that failed rogue check only ([bit 9 ON] + bit 6 OFF + bit 16 ON + bit 18 OFF + [bit 7 OFF])
2397 condition2 = .not. btest(flag, 6) .and. btest(flag, 16) .and. .not. btest(flag, 18) !' AND (FLAG & 64 = 0) AND (FLAG & 65536 = 65536) AND (FLAG & 262144 = 0)'
2398 condition = condition1 .or. condition2
2399 else
2400 ! FLAG test: corrected/selected good data that have passed QC (bits 9,11 OFF) --> data to be assimilated
2401 condition = .not. btest(flag, 9) .and. .not. btest(flag, 11) !' AND (FLAG & 512 = 0) AND (FLAG & 2048 = 0)'
2402 end if
2403 else
2404 ! OFFLINE MODE --> want all observations except data rejected for any reason other than rogue innovation check
2405 condition1 = .not. btest(flag, 9) !' AND (FLAG & 512 = 0)'
2406 ! all good data that passed all QC
2407 ! "good" data that failed rogue check [bit 9 ON, bit 7 OFF, bit 18 OFF]
2408 condition2 = btest(flag, 9) .and. .not. btest(flag, 7) .and. .not. btest(flag, 18) !' AND (FLAG & 512 = 512) AND (FLAG & 128 = 0) AND (FLAG & 262144 = 0)'
2409 condition = condition1 .or. condition2
2410 end if
2411 else if(lTovs) then
2412 ! AMSU-A, AMSU-B/MHS, ATMS, MWHS-2
2413 ! In AMSU case, bit 11 is set for data that are not bias corrected or for unselected channels.
2414 ! BUT unlike other instruments, all AMSU data are bias corrected, whether selected or not
2415 ! so bit 11 = unselected channel (like bit 8 for AIRS/IASI)
2416 ! Bit 9 is set for all other rejections including rogue (9+16) and topography (9+18).
2417 ! In addition, bit 7 is set for channels with bad data or data that should not be assimilated.
2418 if (.not. offlineMode .and. .not. channelIsPassive) then
2419 if (allModeTovs) then
2420 ! FLAG test: all data (selected or not) that have passed QC (bit 9 OFF)
2421 condition1 = .not. btest(flag, 9) !' AND (FLAG & 512 = 0)'
2422 ! FLAG test: uncorrected (bit 6 OFF) data that failed rogue check only (bit (9)/16 ON, 18,7 OFF)
2423 ! NOTE: As all AMSU data are normally bias corrected, query2 will return nothing
2424 condition2 = btest(flag, 16) .and. .not. btest(flag, 6) .and. .not. btest(flag, 18) .and. .not. btest(flag, 7)!' AND (FLAG & 64 = 0) AND (FLAG & 65536 = 65536) AND (FLAG & 262144 = 0) AND (FLAG & 128 = 0)'
2425 condition = condition1 .or. condition2
2426 else
2427 ! FLAG test: selected data (bit 11 OFF) that have passed QC (bit 9 OFF)
2428 condition = .not. btest(flag, 9) .and. .not. btest(flag, 11) !' AND (FLAG & 512 = 0) AND (FLAG & 2048 = 0)'
2429 end if
2430 else ! OFFLINE MODE --> want all observations except data rejected for any reason other than rogue check
2431 condition1 = .not. btest(flag, 9) !' AND (FLAG & 512 = 0)'
2432 ! all good data that passed all QC
2433 ! "good" data that failed rogue check [bit 9 ON, bit 7 OFF, bit 18 OFF]
2434 condition2 = btest(flag, 9) .and. .not. btest(flag, 7) .and. .not. btest(flag, 18) !' AND (FLAG & 512 = 512) AND (FLAG & 128 = 0) AND (FLAG & 262144 = 0)'
2435 condition = condition1 .or. condition2
2436 end if
2437 if (channelIsAllsky) condition = condition .and. .not. btest(flag, 23)
2438 else if(lGeo) then ! CSR case
2439 ! No flag check = all data that have passed QC/filtering
2440 ! (FLAG & 2048 = 0) = bit 11 OFF --> corrected/selected data that have passed QC/filtering
2441 if (allModeCsr .or. offlineMode .or. channelIsPassive) then
2442 condition = .true.
2443 else
2444 condition = .not. btest(flag, 18) ! ' AND (FLAG & 2048 = 0)'
2445 endif
2446 else if (lHyperIr) then ! AIRS, IASI and CRIS
2447 ! (FLAG & 2560 = 0) = bits 9, 11 OFF --> data that passed QC (rogue and other)
2448 ! (FLAG & 11010176 = 0) = bits 7,19,21,23 OFF --> "good" data (corrected/selected or not)! (FLAG & 64 = 64) = bit 6 ON --> bias corrected data
2449 ! (FLAG & 256 = 0) = bit 8 OFF --> passed selction (not blacklisted, UTIL=1)
2450 ! (FLAG & 2048 = 2048) = bit 11 ON
2451 ! (FLAG & 65536 = 65536) = bit 16 ON --> rogue check failure
2452 ! (FLAG & 524288 = 0) = bit 19 OFF --> not surface affected [experimental, bit 11 may not be on if data
2453 ! are to be assimilated]
2454 ! (FLAG & 2097152 = 0) = bit 21 OFF --> not rejected due to model top transmittance
2455 ! (FLAG & 8388608 = 0) = bit 23 OFF --> "clear sky" radiance [experimental, bit 11 may not be on if cloudy
2456 ! data are assimilated]! (FLAG & 128 = 0) = bit 7 OFF --> not shortwave channel during day
2457 ! (FLAG & 512 = 0) = bit 9 OFF --> non-erroneous data that passed O-P rogue check
2458 !! AIRS, IASI:! bit 8 ON: blacklisted/unselected channel (UTIL=0)
2459 ! bit 9 ON: erroneous/suspect data (9), data failed O-P check (9+16)
2460 ! bit 11 ON: cloud (11+23), surface (11+19), model top transmittance (11+21), shortwave channel+daytime (11+7)
2461 ! not bias corrected (11) (with bit 6 OFF)
2462 if (.not. offlineMode .and. .not. channelIsPassive) then
2463 if (allModeHyperIr) then
2464 ! good data that have passed all QC (bits 9 and 7,19,21,23 OFF), corrected/selected or not
2465 condition1 = .not. btest(flag, 9) .and. .not. btest(flag, 7) .and. .not. btest(flag, 19) .and. .not. btest(flag, 21) .and. .not. btest(flag, 23) !' AND (FLAG & 512 = 0) AND (FLAG & 11010176 = 0)'
2466 ! uncorrected (6 OFF, [11 ON]) good data (7,19,21,23 OFF) that failed QC rogue check only (bits [9],16 ON), selected or not
2467 condition2 = .not. btest(flag, 6) .and. btest(flag, 11) .and. .not. btest(flag, 17) .and. .not. btest(flag, 19) .and. .not. btest(flag, 21) .and. .not. btest(flag, 23)
2468 !' AND (FLAG & 64 = 0) AND (FLAG & 65536 = 65536) AND (FLAG & 11010176 = 0)'
2469 condition = condition1 .or. condition2
2470 else
2471 ! corrected data that passed all QC and selection excluding cloud/sfc affected obs
2472 condition = .not. btest(flag, 9) .and. .not. btest(flag, 11) .and. .not. btest(flag, 8) .and. .not. btest(flag, 23) .and. .not. btest(flag, 19)
2473 !' AND (FLAG & 2560 = 0) AND (FLAG & 256 = 0) AND (FLAG & 8388608 = 0) AND (FLAG & 524288 = 0)'
2474 end if
2475 else! OFFLINE MODE --> Want all observations except data rejected for any reason other than innovation rogue check
2476 ! Assumes that type S or N correction has been applied to all data/channels (all data "corrected")
2477 ! data that passed all QC
2478 condition1 = .not. btest(flag, 9) .and. .not. btest(flag, 7) .and. .not. btest(flag, 19) .and. .not. btest(flag, 21) .and. .not. btest(flag, 23)
2479 !' AND (FLAG & 512 = 0) AND (FLAG & 11010176 = 0)'
2480 ! good data (7,19,21,23 OFF) that failed QC rogue check only (bits [9],16 ON)
2481 condition2 = btest(flag, 9) .and. btest(flag, 16) .and. .not. btest(flag, 7) .and. .not. btest(flag, 19) .and. .not. btest(flag, 21) .and. .not. btest(flag, 23) !' AND (FLAG & 65536 = 65536) AND (FLAG & 11010176 = 0)'
2482 condition = condition1 .or. condition2
2483 end if
2484 end if
2485
2486 if (condition) assim = obs_Assimilated
2487
2488 call obs_bodySet_i(obsSpaceData, OBS_ASS, bodyIndex, assim)
2489 end if
2490 end if
2491 end do BODY
2492 end do HEADER
2493
2494 deallocate(instrumentList)
2495
2496 end subroutine bcs_filterObs
2497
2498 !-----------------------------------------
2499 ! bcs_applyBiasCorrection
2500 !-----------------------------------------
2501 subroutine bcs_applyBiasCorrection(obsSpaceData, column, family_opt)
2502 !
2503 !:Purpose: to apply bias correction from OBS_BCOR to
2504 ! obsSpaceData column column.
2505 ! After the call obsSpaceData body column contains the corrected
2506 ! observation or O-F and OBS_BCOR is not modified.
2507 implicit none
2508
2509 ! Arguments:
2510 type(struct_obs), intent(inout) :: obsSpaceData
2511 integer, intent(in) :: column !obsSpaceData column
2512 character(len=2), optional, intent(in) :: family_opt
2513
2514 ! Locals:
2515 integer :: nbcor
2516 integer :: bodyIndex
2517 real(8) :: biascor, Obs
2518 integer :: flag
2519
2520 if (.not. biasActive) return
2521 if (trim(biasMode) /= "apply") return
2522
2523 if (mmpi_myid == 0) write(*,*) 'bcs_applyBiasCorrection: start'
2524
2525 nbcor = 0
2526 call obs_set_current_body_list(obsSpaceData, family_opt)
2527
2528 BODY: do
2529 bodyIndex = obs_getBodyIndex(obsSpaceData)
2530 if (bodyIndex < 0) exit BODY
2531 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
2532 biasCor = obs_bodyElem_r(obsSpaceData, OBS_BCOR, bodyIndex)
2533 if (biasCor /= MPC_missingValue_R8) then
2534 Obs = obs_bodyElem_r(obsSpaceData, column, bodyIndex)
2535 if (Obs /= MPC_missingValue_R8) then
2536 call obs_bodySet_r(obsSpaceData, column, bodyIndex, real(Obs + biasCor, pre_obsReal))
2537 flag = obs_bodyElem_i(obsSpaceData, OBS_FLG, bodyIndex)
2538 flag = ibset(flag, 6)
2539 call obs_bodySet_i(obsSpaceData, OBS_FLG, bodyIndex, flag)
2540 nbcor = nbcor + 1
2541 end if
2542 end if
2543 end do BODY
2544
2545 if (mmpi_myid == 0) then
2546 write(*,*) 'bcs_applyBiasCorrection: apply bias correction for ', nbcor, ' observations'
2547 write(*,*) 'bcs_applyBiasCorrection exiting'
2548 end if
2549
2550 end subroutine bcs_applyBiasCorrection
2551
2552 !-----------------------------------------
2553 ! bcs_refreshBiasCorrection
2554 !-----------------------------------------
2555 subroutine bcs_refreshBiasCorrection(obsSpaceData, columnTrlOnTrlLev)
2556 !
2557 !:Purpose: to apply bias correction from read coefficient file to OBS_VAR
2558 ! After the call OBS_VAR contains the corrected observation
2559 ! and OBS_BCOR is set to applied bias correction
2560 !
2561 implicit none
2562
2563 ! Arguments:
2564 type(struct_obs), intent(inout) :: obsSpaceData
2565 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
2566
2567 if (.not.biasActive) return
2568 if (.not. refreshBiasCorrection) return
2569
2570 if (mmpi_myid == 0) write(*,*) 'bcs_refreshBiasCorrection: start'
2571 call bcs_calcBias(obsSpaceData, columnTrlOnTrlLev)
2572 call bcs_applyBiasCorrection(obsSpaceData, OBS_VAR, "TO")
2573 if (mmpi_myid == 0) write(*,*) 'bcs_refreshBiasCorrection: exit'
2574
2575 end subroutine bcs_refreshBiasCorrection
2576
2577 !-----------------------------------------
2578 ! bcs_getRadiosondeWeight
2579 !-----------------------------------------
2580 subroutine bcs_getRadiosondeWeight(obsSpaceData, lmodify_obserror_opt)
2581 !
2582 !:Purpose: initialize the weights to give more importance to data near radiosonde stations
2583 !
2584 implicit none
2585
2586 ! Arguments:
2587 type(struct_obs), intent(inout) :: obsSpaceData
2588 logical, optional, intent(in) :: lmodify_obserror_opt
2589
2590 ! Locals:
2591 integer :: iobs, headerIndex, idatyp, nobs, bodyIndex, stepIndex
2592 logical :: lmodify_obserror
2593 real(8) :: sigmaObs
2594 type(struct_gsv) :: stateVector_mask, stateVector_mask_4d
2595
2596 lmodify_obserror =.false.
2597
2598 if (present(lmodify_obserror_opt)) lmodify_obserror = lmodify_obserror_opt
2599
2600
2601 if (weightedEstimate) then
2602 call hco_SetupFromFile(hco_mask, './raob_masque.std', 'WEIGHT', GridName_opt='RadiosondeWeight', varName_opt='WT')
2603 call vco_SetupFromFile(vco_mask, './raob_masque.std') ! IN
2604
2605 call gsv_allocate(stateVector_mask, 1, hco_mask, vco_mask, dateStampList_opt=[-1], varNames_opt=["WT"], &
2606 dataKind_opt=4, mpi_local_opt=.true., mpi_distribution_opt="Tiles")
2607 call gsv_allocate(stateVector_mask_4d, tim_nstepobs, hco_mask, vco_mask, dateStampList_opt=[ (-1, stepIndex = 1, tim_nstepobs) ], varNames_opt=["WT"], &
2608 dataKind_opt=4, mpi_local_opt=.true., mpi_distribution_opt="Tiles")
2609
2610 call gio_readFromFile(stateVector_mask, './raob_masque.std', 'WEIGHT', 'O', unitConversion_opt=.false., &
2611 containsFullField_opt=.false.)
2612
2613 do stepIndex = 1, tim_nstepobs
2614 call gsv_copy(stateVector_mask, stateVector_mask_4d, stepIndexOut_opt=stepIndex)
2615 end do
2616 call gsv_deallocate(stateVector_mask)
2617 call col_setVco(column_mask, vco_mask)
2618 nobs = obs_numHeader(obsSpaceData)
2619 call col_allocate(column_mask, nobs, beSilent_opt=.false., varNames_opt=["WT"])
2620
2621 call s2c_nl(stateVector_mask_4d, obsSpaceData, column_mask, hco_mask, &
2622 'NEAREST', varName_opt="WT", moveObsAtPole_opt=.true.)
2623
2624 call obs_set_current_header_list(obsSpaceData, 'TO')
2625 iobs = 0
2626 HEADER: do
2627 headerIndex = obs_getHeaderIndex(obsSpaceData)
2628 if (headerIndex < 0) exit HEADER
2629
2630 ! process only radiance data to be assimilated?
2631 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
2632 if (.not. tvs_isIdBurpTovs(idatyp)) then
2633 write(*,*) 'bcs_getRadiosondeWeight: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
2634 cycle HEADER
2635 end if
2636 iobs = iobs + 1
2637
2638 RadiosondeWeight(iobs) = col_getElem(column_mask, 1, headerIndex)
2639
2640 if (lmodify_obserror) then
2641 call obs_set_current_body_list(obsSpaceData, headerIndex)
2642 BODY: do
2643 bodyIndex = obs_getBodyIndex(obsSpaceData)
2644 if (bodyIndex < 0) exit BODY
2645
2646 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY
2647
2648 sigmaObs = obs_bodyElem_r(obsSpaceData, OBS_OER, bodyIndex)
2649
2650 sigmaObs = sigmaObs / sqrt(RadiosondeWeight(iobs))
2651 call obs_bodySet_r(obsSpaceData, OBS_OER, bodyIndex, sigmaObs)
2652
2653 end do BODY
2654
2655 end if
2656
2657 end do HEADER
2658 call gsv_deallocate(stateVector_mask_4d)
2659 else
2660 RadiosondeWeight(:) = 1.d0
2661 end if
2662
2663 end subroutine bcs_getRadiosondeWeight
2664
2665 !-----------------------------------------
2666 ! bcs_do_regression
2667 !-----------------------------------------
2668 subroutine bcs_do_regression(columnTrlOnTrlLev, obsSpaceData)
2669 !
2670 !:Purpose: compute the bias correction coefficients by linear regresion
2671 !
2672 implicit none
2673
2674 ! Arguments:
2675 type(struct_obs), intent(inout) :: obsSpaceData
2676 type(struct_columnData), intent(inout) :: columnTrlOnTrlLev
2677
2678 ! Locals:
2679 integer :: iSensor, iChannel, npred, nchans, nscan, ndim, ndimmax
2680 integer :: sensorIndex, iPred1, jPred1, iobs
2681 integer :: headerIndex, idatyp, nPredMax, ierr, iFov, iScan, idim
2682 integer :: indxtovs, bodyIndex, chanIndx, predstart, ntot
2683 real(8) :: OmF, sigmaObs, lambda, norm
2684 real(8) :: predictor(NumPredictors)
2685 real(8), allocatable :: Matrix(:,:,:), Vector(:,:)
2686 real(8), allocatable :: matrixMpiGlobal(:,:,:), vectorMpiGlobal(:,:)
2687 real(8), allocatable :: pIMatrix(:,:), OmFBias(:,:), omfBiasMpiGlobal(:,:)
2688 real(8), allocatable :: BMatrixMinusOne(:,:), LineVec(:,:)
2689 integer, allocatable :: OmFCount(:,:), omfCountMpiGlobal(:,:)
2690 character(len=80) :: errorMessage
2691
2692 write(*,*) "bcs_do_regression: start"
2693 if (.not. allocated(trialHeight300m1000)) then
2694 call bcs_getTrialPredictors(obsSpaceData, columnTrlOnTrlLev)
2695 call bcs_computePredictorBiases(obsSpaceData)
2696 end if
2697
2698 call bcs_getRadiosondeWeight(obsSpaceData)
2699
2700 if (outOmFPredCov) call bcs_outputCvOmPPred(obsSpaceData)
2701
2702 SENSORS:do sensorIndex = 1, tvs_nsensors
2703
2704 if (.not. tvs_isReallyPresentMpiGLobal(sensorIndex)) cycle SENSORS
2705
2706 nchans = bias(sensorIndex)%numChannels
2707 nscan = bias(sensorIndex)%numscan
2708 npredMax = maxval(bias(sensorIndex)%chans(:)%numActivePredictors)
2709
2710 if (mimicSatbcor) then
2711 ndimmax = npredMax
2712 allocate(OmFBias(nchans,nscan))
2713 OmFBias(:,:) = 0.d0
2714 else
2715 ndimmax = npredMax + nscan - 1
2716 end if
2717
2718 allocate(OmFCount(nchans,nscan))
2719 OmFCount(:,:) = 0
2720
2721 allocate(Matrix(nchans,ndimmax,ndimmax))
2722 Matrix(:,:,:) = 0.d0
2723
2724 allocate(Vector(nchans,ndimmax))
2725 Vector(:,:) = 0.d0
2726
2727 allocate(LineVec(1,ndimmax))
2728
2729 allocate(pIMatrix(ndimmax,ndimmax))
2730
2731
2732 ! First pass throught ObsSpaceData to estimate scan biases and count data
2733
2734 call obs_set_current_header_list(obsSpaceData, 'TO')
2735 HEADER1: do
2736 headerIndex = obs_getHeaderIndex(obsSpaceData)
2737 if (headerIndex < 0) exit HEADER1
2738
2739 ! process only radiance data to be assimilated?
2740 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
2741 if (.not. tvs_isIdBurpTovs(idatyp)) then
2742 write(*,*) 'bcs_do_regression: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
2743 cycle HEADER1
2744 end if
2745 indxtovs = tvs_tovsIndex(headerIndex)
2746 if (indxtovs < 0) cycle HEADER1
2747
2748 iSensor = tvs_lsensor(indxTovs)
2749 if (iSensor /= sensorIndex) cycle HEADER1
2750 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
2751 if (nscan > 1) then
2752 iScan = iFov
2753 else
2754 iScan = 1
2755 end if
2756
2757 call obs_set_current_body_list(obsSpaceData, headerIndex)
2758 BODY1: do
2759 bodyIndex = obs_getBodyIndex(obsSpaceData)
2760 if (bodyIndex < 0) exit BODY1
2761
2762 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY1
2763 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
2764 if (chanindx > 0) then
2765 if (mimicSatBcor) then
2766 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
2767 OmFBias(chanIndx,iScan) = OmFBias(chanIndx,iScan) + OmF
2768 end if
2769 OmFCount(chanIndx,iScan) = OmFCount(chanIndx,iScan) + 1
2770 end if
2771 end do BODY1
2772 end do HEADER1
2773
2774 if (mimicSatbcor) allocate(omfBiasMpiGlobal(nchans,nscan))
2775
2776 allocate(omfCountMpiGlobal(nchans,nscan))
2777
2778 if (mimicSatbcor) then
2779 call mmpi_reduce_sumR8_2d( OmFBias, omfBiasMpiGlobal, 0, "GRID" )
2780 end if
2781 call rpn_comm_reduce(OmFCount, omfCountMpiGlobal, size(omfCountMpiGlobal), "mpi_integer", "MPI_SUM", 0, "GRID", ierr)
2782
2783 if (ierr /= 0) then
2784 write(errorMessage,*) "bcs_do_regression: MPI communication error 2", ierr
2785 call utl_abort(errorMessage)
2786 end if
2787 if (mimicSatbcor) then
2788 if (mmpi_myId == 0) then
2789 where(omfCountMpiGlobal == 0) omfBiasMpiGlobal = 0.d0
2790 where(omfCountMpiGlobal > 0) omfBiasMpiGlobal = omfBiasMpiGlobal / omfCountMpiGlobal
2791 end if
2792 call rpn_comm_bcast(omfBiasMpiGlobal, size(omfBiasMpiGlobal), "mpi_double_precision", 0, "GRID", ierr)
2793 if (ierr /= 0) then
2794 write(errorMessage,*) "bcs_do_regression: MPI communication error 3", ierr
2795 call utl_abort(errorMessage)
2796 end if
2797 do iChannel = 1, nchans
2798 bias(sensorIndex)%chans(iChannel)%coeff_fov(:) = omfBiasMpiGlobal(iChannel, :)
2799 end do
2800 deallocate(omfBiasMpiGlobal)
2801 end if
2802
2803 ! Second pass to fill matrices and vectors
2804 call obs_set_current_header_list(obsSpaceData, 'TO')
2805 iobs = 0
2806 HEADER2: do
2807 headerIndex = obs_getHeaderIndex(obsSpaceData)
2808 if (headerIndex < 0) exit HEADER2
2809
2810 ! process only radiance data to be assimilated?
2811 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
2812 if (.not. tvs_isIdBurpTovs(idatyp)) then
2813 write(*,*) 'bcs_do_regression: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
2814 cycle HEADER2
2815 end if
2816 iobs = iobs + 1
2817 indxtovs = tvs_tovsIndex(headerIndex)
2818 if (indxtovs < 0) cycle HEADER2
2819
2820 iSensor = tvs_lsensor(indxTovs)
2821 if (iSensor /= sensorIndex) cycle HEADER2
2822
2823 call obs_set_current_body_list(obsSpaceData, headerIndex)
2824 iFov = obs_headElem_i(obsSpaceData, OBS_FOV, headerIndex)
2825 if (nscan > 1) then
2826 iScan = iFov
2827 else
2828 iScan = 1
2829 end if
2830 BODY2: do
2831 bodyIndex = obs_getBodyIndex(obsSpaceData)
2832 if (bodyIndex < 0) exit BODY2
2833 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY2
2834 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
2835 if (chanIndx > 0) then
2836 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
2837 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
2838
2839 if (mimicSatbcor) OmF = OmF - bias(sensorIndex)%chans(chanIndx)%coeff_fov(iScan)
2840
2841 LineVec(:,:) = 0.d0
2842
2843 if (mimicSatbcor) then
2844 idim = 0
2845 predstart = 1
2846 lambda = 1.d0
2847 else
2848 LineVec(1,iScan) = 1.d0
2849 idim = nscan
2850 predstart = 2
2851 sigmaObs = obs_bodyElem_r(obsSpaceData, OBS_OER, bodyIndex)
2852 lambda = 1.d0 / (sigmaObs ** 2)
2853 end if
2854
2855 lambda = lambda * RadiosondeWeight(iobs)
2856
2857 do iPred1 = predstart, bias(iSensor)%chans(chanIndx)%NumActivePredictors
2858 jPred1 = bias(iSensor)%chans(chanIndx)%PredictorIndex(iPred1)
2859 idim = idim + 1
2860 LineVec(1,idim) = predictor(jPred1)
2861 end do
2862 Matrix(chanindx,:,:) = Matrix(chanindx,:,:) + matmul(transpose(LineVec),LineVec) * lambda
2863 Vector(chanIndx,:) = Vector(chanIndx,:) + LineVec(1,:) * OmF * lambda
2864 end if
2865 end do BODY2
2866 end do HEADER2
2867
2868 if (mmpi_myId == 0) then
2869 allocate(matrixMpiGlobal(nchans,ndimmax,ndimmax))
2870 allocate(vectorMpiGlobal(nchans,ndimmax))
2871 else
2872 allocate(matrixMpiGlobal(1,1,1))
2873 allocate(vectorMpiGlobal(1,1))
2874 end if
2875
2876 ! communication MPI pour tout avoir sur tache 0
2877 call mmpi_reduce_sumR8_3d( Matrix, matrixMpiGlobal, 0, "GRID" )
2878 call mmpi_reduce_sumR8_2d( Vector, vectorMpiGlobal, 0, "GRID" )
2879
2880 do iChannel = 1, nchans
2881
2882 if (mmpi_myId == 0) then
2883 ntot = sum(omfCountMpiGlobal(iChannel, :))
2884 bias(sensorIndex)%chans(iChannel)%coeff_nobs = ntot
2885 if (ntot > 0 .and. .not. mimicSatbcor) then
2886 norm = 1.d0 / (ntot)
2887 matrixMpiGlobal(iChannel,:,:) = matrixMpiGlobal(iChannel,:,:) * norm
2888 vectorMpiGlobal(iChannel,:) = vectorMpiGlobal(iChannel,:) * norm
2889 end if
2890
2891 nPred = bias(sensorIndex)%chans(iChannel)%numActivePredictors
2892 if (mimicSatbcor) then
2893 ndim = npred
2894 else
2895 ndim = npred + nscan -1
2896 allocate(BMatrixMinusOne(ndim,ndim))
2897 BMatrixMinusOne(:,:) = 0.d0
2898 BMatrixMinusOne(1:nscan,1:nscan) = matmul(bias(sensorIndex)%BMinusHalfScanBias, bias(sensorIndex)%BMinusHalfScanBias)
2899 do iPred1 = 2, bias(sensorIndex)%chans(iChannel)%numActivePredictors
2900 BMatrixMinusOne(nscan - 1 + iPred1,nscan - 1 + iPred1) = (1.d0 / (bias(sensorIndex)%chans(iChannel)%stddev(iPred1)) ** 2)
2901 end do
2902 matrixMpiGlobal(iChannel,1:ndim,1:ndim) = matrixMpiGlobal(iChannel,1:ndim,1:ndim) + BMatrixMinusOne(:,:)
2903 deallocate(BMatrixMinusOne)
2904 end if
2905
2906 pIMatrix(:,:) = 0.d0
2907 call utl_pseudo_inverse(matrixMpiGlobal(iChannel, 1:ndim, 1:ndim), pIMatrix(1:ndim, 1:ndim))
2908 LineVec(1,1:ndim) = matmul(pIMatrix(1:ndim,1:ndim), vectorMpiGlobal(iChannel,1:ndim))
2909 !call dsymv("L", ndim, 1.d0, pIMatrix, ndim,vectorMpiGlobal(iChannel,:), 1, 0.d0, LineVec(1,1:ndim), 1)
2910 end if
2911
2912 call rpn_comm_bcast(ndim, 1, "mpi_integer", 0, "GRID", ierr)
2913 call rpn_comm_bcast(npred, 1, "mpi_integer", 0, "GRID", ierr)
2914
2915 call rpn_comm_bcast(LineVec(1,1:ndim), ndim, "mpi_double_precision", 0, "GRID", ierr)
2916 if (ierr /= 0) then
2917 write(errorMessage,*) "bcs_do_regression: MPI communication error 6", ierr
2918 call utl_abort(errorMessage)
2919 end if
2920
2921 if (outCoeffCov) then
2922 allocate (bias(sensorIndex)%chans(iChannel)%coeffCov(ndim,ndim))
2923 call rpn_comm_bcast(pIMatrix(1:ndim, 1:ndim), ndim * ndim, "mpi_double_precision", 0, "GRID", ierr)
2924 bias(sensorIndex)%chans(iChannel)%coeffCov(:,:) = pIMatrix(1:ndim,1:ndim)
2925 end if
2926
2927 if (mimicSatbcor) then
2928 bias(sensorIndex)%chans(iChannel)%coeff(:) = LineVec(1,1:npred)
2929 else
2930 bias(sensorIndex)%chans(iChannel)%coeff_fov(:) = LineVec(1,1:nscan)
2931 bias(sensorIndex)%chans(iChannel)%coeff(1) = 0.d0
2932 bias(sensorIndex)%chans(iChannel)%coeff(2:) = LineVec(1,nscan+1:ndim)
2933 end if
2934
2935 end do
2936
2937 deallocate(LineVec)
2938 deallocate(Matrix)
2939 deallocate(Vector )
2940 deallocate(omfCountMpiGlobal)
2941 deallocate(matrixMpiGlobal)
2942 deallocate(vectorMpiGlobal)
2943 deallocate(pIMatrix)
2944 if (allocated(OmFBias)) deallocate(OmFBias)
2945 deallocate(OmFCount)
2946
2947 end do SENSORS
2948
2949 end subroutine bcs_do_regression
2950
2951 !-----------------------------------------
2952 ! bcs_outputCvOmPPred
2953 !-----------------------------------------
2954 subroutine bcs_outputCvOmPPred(obsSpaceData)
2955 !
2956 !:Purpose: compute and output OmF-predictors covariance and correlation matrices
2957 !
2958 implicit none
2959
2960 ! Arguments:
2961 type(struct_obs), intent(inout) :: obsSpaceData
2962
2963 ! Locals:
2964 integer :: sensorIndex, headerIndex, bodyIndex, channelIndex, predictorIndex,predictorIndex2,nchans
2965 integer :: idatyp, indxtovs, iSensor, chanIndx, Iobs, ierr
2966 Real(8):: OmF
2967 real(8), allocatable :: OmFBias(:), Matrix(:,:,:), PredBias(:,:)
2968 integer, allocatable :: Count(:), CountMpiGlobal(:)
2969 real(8), allocatable :: OmFBiasMpiGlobal(:), predBiasMpiGlobal(:,:), MatrixMpiGLobal(:,:,:)
2970 character(len=128) :: errorMessage
2971 real(8) :: vector(1,numPredictors), predictor(numPredictors),correlation(numPredictors,numPredictors)
2972 real(8) :: sigma(numPredictors)
2973 integer :: iuncov, iuncorr
2974
2975 write(*,*) "bcs_outputCvOmPPred: Starting"
2976
2977 SENSORS:do sensorIndex = 1, tvs_nsensors
2978
2979 if (.not. tvs_isReallyPresentMpiGLobal(sensorIndex)) cycle SENSORS
2980 write(*,*) "sensor ", sensorIndex
2981
2982 nchans = bias(sensorIndex)%numChannels ! from bcif
2983
2984 allocate(OmFBias(nchans))
2985 OmFBias(:) = 0.d0
2986
2987 allocate(predBias(nchans,numPredictors))
2988 predBias(:,:) = 0.d0
2989
2990 allocate(Count(nchans))
2991 Count(:) = 0
2992
2993 iobs = 0
2994 ! First pass throught ObsSpaceData to estimate biases and count data
2995 call obs_set_current_header_list(obsSpaceData, 'TO')
2996 HEADER1: do
2997 headerIndex = obs_getHeaderIndex(obsSpaceData)
2998 if (headerIndex < 0) exit HEADER1
2999 ! process only radiance data to be assimilated?
3000 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
3001 if (.not. tvs_isIdBurpTovs(idatyp)) then
3002 write(*,*) 'bcs_outputCvOmPPred: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
3003 cycle HEADER1
3004 end if
3005 iobs = iobs + 1
3006 indxtovs = tvs_tovsIndex(headerIndex)
3007 if (indxtovs < 0) cycle HEADER1
3008 iSensor = tvs_lsensor(indxTovs)
3009 if (iSensor /= sensorIndex) cycle HEADER1
3010
3011 call obs_set_current_body_list(obsSpaceData, headerIndex)
3012 BODY1: do
3013 bodyIndex = obs_getBodyIndex(obsSpaceData)
3014 if (bodyIndex < 0) exit BODY1
3015 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY1
3016 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
3017 if (chanindx > 0) then
3018 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
3019 OmFBias(chanIndx) = OmFBias(chanIndx) + OmF
3020 count(chanIndx) = count(chanIndx) + 1
3021 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
3022 predBias(chanIndx,:) = predBias(chanIndx,:) + predictor(:)
3023 end if
3024 end do BODY1
3025 end do HEADER1
3026
3027 allocate(omfBiasMpiGlobal(nchans))
3028 allocate(countMpiGlobal(nchans))
3029 allocate(predBiasMpiGlobal(nchans,numPredictors))
3030
3031 call mmpi_reduce_sumR8_1d(OmFBias, omfBiasMpiGlobal, 0, "GRID" )
3032 call mmpi_reduce_sumR8_2d(predBias, predBiasMpiGlobal, 0, "GRID" )
3033
3034 call rpn_comm_reduce(count, countMpiGlobal, size(countMpiGlobal), "mpi_integer", "MPI_SUM", 0, "GRID", ierr)
3035 if (ierr /= 0) then
3036 write(errorMessage,*) "bcs_outputCvOmPPred: MPI communication error 1", ierr
3037 call utl_abort(errorMessage)
3038 end if
3039
3040 if (mmpi_myId == 0) then
3041 where(countMpiGlobal == 0) omfBiasMpiGlobal = 0.d0
3042 where(countMpiGlobal > 0) omfBiasMpiGlobal = omfBiasMpiGlobal / countMpiGlobal
3043 do channelIndex =1, nchans
3044 if (countMpiGlobal(channelIndex) == 0) predBiasMpiGlobal(channelIndex,:) = 0.d0
3045 if (countMpiGlobal(channelIndex) > 0) predBiasMpiGlobal(channelIndex,:) = predBiasMpiGlobal(channelIndex,:) / countMpiGlobal(channelIndex)
3046 end do
3047 end if
3048 call rpn_comm_bcast(omfBiasMpiGlobal, size(omfBiasMpiGlobal), "mpi_double_precision", 0, "GRID", ierr)
3049 if (ierr /= 0) then
3050 write(errorMessage,*) "bcs_outputCvOmPPred: MPI communication error 4", ierr
3051 call utl_abort(errorMessage)
3052 end if
3053 call rpn_comm_bcast(predBiasMpiGlobal, size(predBiasMpiGlobal), "mpi_double_precision", 0, "GRID", ierr)
3054 if (ierr /= 0) then
3055 write(errorMessage,*) "bcs_outputCvOmPPred: MPI communication error 3", ierr
3056 call utl_abort(errorMessage)
3057 end if
3058 call rpn_comm_bcast(countMpiGlobal, size(countMpiGlobal), "mpi_integer", 0, "GRID", ierr)
3059 if (ierr /= 0) then
3060 write(errorMessage,*) "bcs_outputCvOmPPred: MPI communication error 4", ierr
3061 call utl_abort(errorMessage)
3062 end if
3063
3064 deallocate(OmFBias)
3065 deallocate(predBias)
3066 deallocate(Count)
3067 allocate(matrix(nchans,numPredictors,numPredictors))
3068 matrix(:,:,:) = 0.d0
3069
3070 ! Second pass to fill covariance Matrix
3071 call obs_set_current_header_list(obsSpaceData, 'TO')
3072 iobs = 0
3073 HEADER2: do
3074 headerIndex = obs_getHeaderIndex(obsSpaceData)
3075 if (headerIndex < 0) exit HEADER2
3076
3077 ! process only radiance data to be assimilated?
3078 idatyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
3079 if (.not. tvs_isIdBurpTovs(idatyp)) then
3080 write(*,*) 'bcs_outputCvOmPPred: warning unknown radiance codtyp present check NAMTOVSINST', idatyp
3081 cycle HEADER2
3082 end if
3083 iobs = iobs + 1
3084 indxtovs = tvs_tovsIndex(headerIndex)
3085 if (indxtovs < 0) cycle HEADER2
3086
3087 iSensor = tvs_lsensor(indxTovs)
3088 if (iSensor /= sensorIndex) cycle HEADER2
3089
3090 call obs_set_current_body_list(obsSpaceData, headerIndex)
3091 BODY2: do
3092 bodyIndex = obs_getBodyIndex(obsSpaceData)
3093 if (bodyIndex < 0) exit BODY2
3094 if (obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) /= obs_assimilated) cycle BODY2
3095 call bcs_getChannelIndex(obsSpaceData, iSensor, chanIndx, bodyIndex)
3096 if (chanIndx > 0) then
3097 call bcs_getPredictors(predictor, headerIndex, iobs, chanIndx, obsSpaceData)
3098 predictor(:) = predictor(:) - predBiasMpiGLobal(chanIndx,:)
3099 OmF = obs_bodyElem_r(obsSpaceData, OBS_OMP, bodyIndex)
3100 OmF = OmF - omfBiasMpiGlobal(chanIndx)
3101 vector(1,1) = OmF
3102 vector(1,2:numPredictors) = predictor(2:numPredictors)
3103 Matrix(chanindx,:,:) = Matrix(chanindx,:,:) + matmul(transpose(vector),vector)
3104 end if
3105 end do BODY2
3106 end do HEADER2
3107
3108 if (mmpi_myId == 0) then
3109 allocate(matrixMpiGlobal(nchans,numPredictors,numPredictors))
3110 else
3111 allocate(matrixMpiGlobal(1,1,1))
3112 end if
3113
3114 ! communication MPI pour tout avoir sur tache 0
3115 call mmpi_reduce_sumR8_3d(matrix, matrixMpiGlobal, 0, "GRID" )
3116 deallocate(matrix)
3117 deallocate(OmFBiasMpiGLobal)
3118 deallocate(predBiasMpiGLobal)
3119 if (mmpi_myId == 0) then
3120 call utl_open_asciifile("covarianceMatrix_" // trim(tvs_instrumentName(sensorIndex)) // &
3121 "_" // trim(tvs_satelliteName(sensorIndex)) // ".dat", iuncov)
3122 call utl_open_asciifile("correlationMatrix_" // trim(tvs_instrumentName(sensorIndex)) // &
3123 "_" // trim(tvs_satelliteName(sensorIndex)) // ".dat", iuncorr)
3124 do channelIndex = 1, nchans
3125 if (countMpiGlobal(channelIndex) > 1) then
3126 matrixMpiGlobal(channelIndex,:,:) = matrixMpiGlobal(channelIndex,:,:) / countMpiGlobal(channelIndex)
3127
3128 write(iuncov,*) "OmF Pred covariance Matrix for channel ", &
3129 bias(sensorIndex)%chans(channelIndex)%channelNum, "instrument ", &
3130 trim(tvs_instrumentName(sensorIndex))," ", &
3131 trim(tvs_satelliteName(sensorIndex))
3132 write(iuncov,'(10x,A6)',advance="no") "OmF"
3133 do predictorIndex = 2, numPredictors
3134 write(iuncov,'(T6,A6,1x)',advance="no") predTab(predictorIndex)
3135 end do
3136 write(iuncov,*)
3137 write(iuncov,'(A6)',advance="no") "Omf"
3138 write(iuncov,'(100f12.6)') matrixMpiGlobal(channelIndex,1,:)
3139 do predictorIndex = 2, numPredictors
3140 write(iuncov,'(A6)',advance="no") predTab(predictorIndex)
3141 write(iuncov,'(100f12.6)') matrixMpiGlobal(channelIndex,predictorIndex,:)
3142 end do
3143 sigma(:) = 0
3144 do predictorIndex = 1,numPredictors
3145 if ( matrixMpiGlobal(channelIndex,predictorIndex,predictorIndex) >0.d0) &
3146 sigma(predictorIndex) = sqrt(matrixMpiGlobal(channelIndex,predictorIndex,predictorIndex))
3147 end do
3148 do predictorIndex = 1, numPredictors
3149 do predictorIndex2 =1, numPredictors
3150 correlation(predictorIndex, predictorIndex2) = &
3151 matrixMpiGlobal(channelIndex,predictorIndex,predictorIndex2) / &
3152 (sigma(predictorIndex) * sigma(predictorIndex2) )
3153 end do
3154 end do
3155 write(iuncorr,*) "OmF Pred correlation Matrix for channel ", &
3156 bias(sensorIndex)%chans(channelIndex)%channelNum,"instrument ", &
3157 trim(tvs_instrumentName(sensorIndex))," ", &
3158 trim(tvs_satelliteName(sensorIndex))
3159 write(iuncorr,'(10x,A6)',advance="no") "OmF"
3160 do predictorIndex = 2, numPredictors
3161 write(iuncorr,'(T6,A6,1x)',advance="no") predTab(predictorIndex)
3162 end do
3163 write(iuncorr,*)
3164 write(iuncorr,'(A6)',advance="no") "Omf"
3165 write(iuncorr,'(100f12.6)') correlation(1,:)
3166 do predictorIndex = 2, numPredictors
3167 write(iuncorr,'(A6)',advance="no") predTab(predictorIndex)
3168 write(iuncorr,'(100f12.6)') correlation(predictorIndex,:)
3169 end do
3170 end if
3171 end do
3172 ierr = fclos(iuncov)
3173 ierr = fclos(iuncorr)
3174 end if
3175
3176 deallocate(countMpiGlobal)
3177 deallocate(matrixMpiGlobal)
3178
3179 end do SENSORS
3180
3181 end subroutine bcs_outputCvOmPPred
3182
3183 !----------------------
3184 ! bcs_Finalize
3185 !----------------------
3186 subroutine bcs_Finalize
3187 !
3188 !:Purpose: release allocated memory for the module
3189 !
3190 implicit none
3191
3192 ! Locals:
3193 integer :: iSensor, iChannel
3194
3195 if (.not. biasActive) return
3196
3197 if (allocated(trialHeight300m1000)) deallocate(trialHeight300m1000)
3198 if (allocated(trialHeight50m200)) deallocate(trialHeight50m200)
3199 if (allocated(trialHeight1m10)) deallocate(trialHeight1m10)
3200 if (allocated(trialHeight5m50)) deallocate(trialHeight5m50)
3201 if (allocated(trialTG)) deallocate(trialTG)
3202 if (allocated(RadiosondeWeight)) deallocate(RadiosondeWeight)
3203
3204 do iSensor = 1, tvs_nSensors
3205 if (allocated(bias(iSensor)%BHalfScanBias)) &
3206 deallocate(bias(iSensor)%BHalfScanBias)
3207 if (allocated(bias(iSensor)%BMinusHalfScanBias)) &
3208 deallocate(bias(iSensor)%BMinusHalfScanBias)
3209 do iChannel =1, bias(iSensor)%numChannels
3210 deallocate(bias(iSensor)%chans(iChannel)%stddev)
3211 deallocate(bias(iSensor)%chans(iChannel)%coeffIncr)
3212 deallocate(bias(iSensor)%chans(iChannel)%predictorIndex)
3213 if (allocated(bias(iSensor)%chans(iChannel)%coeffIncr_fov)) deallocate(bias(iSensor)%chans(iChannel)%coeffIncr_fov)
3214 deallocate(bias(iSensor)%chans(iChannel)%coeff_offset)
3215 if (allocated(bias(iSensor)%chans(iChannel)%coeff)) deallocate(bias(iSensor)%chans(iChannel)%coeff)
3216 if (allocated(bias(iSensor)%chans(iChannel)%coeff_fov)) deallocate(bias(iSensor)%chans(iChannel)%coeff_fov)
3217 if (allocated(bias(iSensor)%chans(iChannel)%coeffCov)) deallocate(bias(iSensor)%chans(iChannel)%coeffCov)
3218 end do
3219 deallocate(bias(iSensor)%chans)
3220 end do
3221
3222 end subroutine bcs_Finalize
3223
3224 !-----------------------------
3225 ! InstrNametoCoeffFileName
3226 !-----------------------------
3227 function InstrNametoCoeffFileName(nameIn) result(nameOut)
3228 implicit none
3229
3230 ! Arguments:
3231 character(len=10), intent(in) :: nameIn
3232 ! Result:
3233 character(len=10) :: nameOut
3234
3235 ! Locals:
3236 character(len=10) :: temp_instrName
3237 integer :: ierr
3238
3239 temp_instrName = nameIn
3240 ierr = clib_tolower(temp_instrName)
3241 if (trim(temp_instrName) == 'mhs') then
3242 nameOut = 'amsub'
3243 else if (trim(temp_instrName) == 'goesimager') then
3244 nameOut = 'cgoes'
3245 else if (trim(temp_instrName) == 'gmsmtsat') then
3246 nameOut = 'mtsat'
3247 else if (trim(temp_instrName) == 'mviri') then
3248 nameOut = 'mets7'
3249 else
3250 nameOut = temp_instrName
3251 end if
3252
3253 end function InstrNametoCoeffFileName
3254
3255 !-----------------------------
3256 ! InstrNameinCoeffFile
3257 !-----------------------------
3258 function InstrNameinCoeffFile(nameIn) result(nameOut)
3259 implicit none
3260
3261 ! Arguments:
3262 character(len=10), intent(in) :: nameIn
3263 ! Result:
3264 character(len=10) :: nameOut
3265
3266 if (trim(nameIn) == 'MHS') then
3267 nameOut = 'AMSUB'
3268 else if (trim(nameIn) == 'GOESIMAGER') then
3269 nameOut = 'CGOES'
3270 else if (trim(nameIn) == 'GMSMTSAT') then
3271 nameOut = 'MTSAT'
3272 else if (trim(nameIn) == 'MVIRI') then
3273 nameOut = 'METS7'
3274 else
3275 nameOut = nameIn
3276 end if
3277
3278 end function InstrNameinCoeffFile
3279
3280 !-----------------------------
3281 ! SatNameinCoeffFile
3282 !-----------------------------
3283 function SatNameinCoeffFile(nameIn) result(nameOut)
3284 implicit none
3285
3286 ! Arguments:
3287 character(len=10), intent(in) :: nameIn
3288 ! Result:
3289 character(len=10) :: nameOut
3290
3291 if (trim(nameIn) == 'MSG1') then
3292 nameOut = 'METSAT8'
3293 else if (trim(nameIn) == 'MSG2') then
3294 nameOut = 'METSAT9'
3295 else if (trim(nameIn) == 'MSG3') then
3296 nameOut = 'METSAT10'
3297 else if (trim(nameIn) == 'MSG4') then
3298 nameOut = 'METSAT11'
3299 else if (trim(nameIn) == 'METEOSAT7') then
3300 nameOut = 'METSAT7'
3301 else
3302 nameOut = nameIn
3303 end if
3304
3305 end function SatNameinCoeffFile
3306
3307 !-----------------------------------------
3308 ! read_bcif
3309 !-----------------------------------------
3310 subroutine read_bcif(bcifFile, hspec, ncan, can, bcmode, bctype, npred, pred, global_opt, exitcode)
3311 !
3312 !:Purpose: to read channel-specific bias correction (BC) information (predictors) for instrument from BCIF.
3313 !
3314 implicit none
3315
3316 ! Arguments:
3317 character(len=*), intent(in) :: bcifFile
3318 logical, intent(in) :: hspec
3319 integer, intent(out) :: exitcode
3320 integer, intent(out) :: ncan
3321 integer, intent(out) :: can(tvs_maxchannelnumber)
3322 integer, intent(out) :: npred(tvs_maxchannelnumber)
3323 character(len=3), intent(in) :: global_opt
3324 character(len=1), intent(out) :: bcmode(tvs_maxchannelnumber)
3325 character(len=1), intent(out) :: bctype(tvs_maxchannelnumber)
3326 character(len=2), intent(out) :: pred(tvs_maxchannelnumber,numpredictorsBCIF)
3327
3328 ! Locals:
3329 character(len=7) :: instrum
3330 integer :: i, j, ier, ii, iun
3331 character(len=64) :: line
3332 integer :: xcan, xnpred, chknp
3333 character(len=1) :: xbcmode, xbctype
3334 character(len=2) :: xpred(numpredictors)
3335
3336 ! Reads channel-specific bias correction (BC) information (predictors) for instrument from BCIF.
3337 ! Channel 0 values are global or default values (optionally applied to all channels).
3338 ! Returns BC information for all channels to calling routine.
3339 !
3340 ! Sample BCIF
3341 ! AMSUA 15 <--- instrument and number of channels
3342 !CHAN MODE TYPE NPRED PRED1 PRED2 PRED3 PRED4 PRED5 PRED6
3343 ! 0 D C 4 T1 T2 T3 T4 XX XX <--- channel "0" global or default values
3344 ! 1 D C 2 T1 T2 XX XX XX XX
3345 ! 2 D C 3 BT T1 T2 XX XX XX
3346 ! 3 S C 2 T3 T4 XX XX XX XX
3347 ! ....
3348 ! ....
3349 ! =================== 24 APRIL 2014 LIST-DIRECTED I/O VERSION ==============================================
3350 ! CALL read_bcif(iunbc, bc_instrum, bc_ncan, bc_can, bc_mode, bc_type, bc_npred, bc_pred, global_opt, exitcode)
3351 !
3352 ! global_opt = NON Read channel-specific data for ALL ncan channels from BCIF (channel 0 ignored)
3353 ! OUI Read channel 0 data and apply to all ncan channels (global values)
3354 ! DEF Read channel 0 data and apply as default values for all ncan channels;
3355 ! then scan the rest of the BCIF for any channel-specific data that will
3356 ! override the default values.
3357 !
3358 ! NOTE: For hyperspectral instruments (e.g. AIRS, IASI, CrIS) the BCIF must always contain records for ALL ncan channels.
3359 ! If global_opt = OUI, only the channel numbers are needed in column 1 (CHAN) to get the list
3360 ! of channel numbers.
3361 ! If global_opt = DEF, other column data (MODE, TYPE, NPRED, PRED1,...) are entered only for
3362 ! those channels for which the default (channel 0) values are to be overridden.
3363 !
3364 ! For standard instruments (AMSU, SSM/I, SSMIS), with consecutive channels 1,2,3,...,ncan:
3365 ! If global_opt = OUI, only the channel 0 record is needed in the BCIF (any other records after
3366 ! channel 0 are ignored (not read).
3367 ! If global_opt = DEF, the channel 0 record (default values) and only records for those channels
3368 ! for which values are different from defaults are needed in the BCIF.
3369
3370 exitcode = -1
3371
3372 iun = 0
3373 ier = fnom(iun, bcifFile, 'FMT', 0)
3374 if (ier /= 0) then
3375 call utl_abort('read_bcif: ERROR - Problem opening the bcif file!' // trim(bcifFile))
3376 end if
3377
3378 read(iun,*) instrum, ncan
3379 read(iun,'(A64)') line
3380
3381 ! For GLOBAL option, read global values from first line (channel 0) and clone to all channels
3382 if (global_opt == 'OUI' .or. global_opt == 'DEF') then
3383 ! Read channel 0 information
3384 read(iun, *, iostat=ier) can(1), bcmode(1), bctype(1), npred(1), (pred(1,j), j = 1, numpredictorsbcif)
3385 if (ier /= 0) then
3386 write(*,*) 'read_BCIF: Error reading channel 0 data!'
3387 exitcode = ier
3388 return
3389 end if
3390 if (can(1) /= 0) then
3391 write(*,*) 'read_BCIF: Channel 0 global values not found!'
3392 exitcode = -1
3393 return
3394 end if
3395 ! Clone channel 0 information to all ncan channels
3396 if (.not. hspec) then
3397 ! For instruments with consecutive channels 1,2,3,...ncan (e.g. AMSU, SSM/I)
3398 ! -- no need to read the channel numbers from the BCIF
3399 do i = 2, ncan+1
3400 can(i) = i - 1
3401 bcmode(i) = bcmode(1)
3402 bctype(i) = bctype(1)
3403 npred(i) = npred(1)
3404 do j = 1, numpredictorsbcif
3405 pred(i,j) = pred(1,j)
3406 end do
3407 end do
3408 else
3409 ! For hyperspectral instruments (channel subsets), read the channel numbers from the BCIF
3410 do i = 2, ncan + 1
3411 read(iun, *, iostat=ier) xcan
3412 if (ier /= 0) then
3413 write(*,*) 'read_BCIF: Error reading channel numbers!'
3414 exitcode = ier
3415 return
3416 end if
3417 can(i) = xcan
3418 bcmode(i) = bcmode(1)
3419 bctype(i) = bctype(1)
3420 npred(i) = npred(1)
3421 do j = 1, numpredictorsbcif
3422 pred(i,j) = pred(1,j)
3423 end do
3424 end do
3425 ! Reposition the file to just after channel 0 record
3426 rewind (iun)
3427 read(iun,*) instrum, ncan
3428 read(iun,'(A64)') line
3429 read(iun,*,iostat=ier) xcan, xbcmode, xbctype, xnpred, (xpred(j), j = 1, numpredictorsbcif)
3430 end if
3431 ! For global_opt == 'DEF' check for channel-specific information and overwrite the default (channel 0) values
3432 ! for the channel with the values from the file
3433 if (global_opt == 'DEF') then
3434 if (.not. hspec) then
3435 do
3436 read(iun,*,iostat=ier) xcan, xbcmode, xbctype, xnpred, (xpred(j), j = 1, numpredictorsbcif)
3437 if (ier < 0) exit
3438 if (ier > 0) then
3439 write(*,*) 'read_BCIF: Error reading file!'
3440 exitcode = ier
3441 return
3442 end if
3443 ii = xcan + 1
3444 if (ii > ncan + 1) then
3445 write(*,*) 'read_BCIF: Channel number in BCIF exceeds number of channels!'
3446 write(*,'(A,1X,I4,1X,I4)') ' Channel, ncan = ', xcan, ncan
3447 exitcode = -1
3448 return
3449 end if
3450 bcmode(ii) = xbcmode
3451 bctype(ii) = xbctype
3452 npred(ii) = xnpred
3453 do j = 1, numpredictorsbcif
3454 pred(ii,j) = xpred(j)
3455 end do
3456 end do
3457 else
3458 ! For hyperspectral instruments
3459 do i = 2, ncan + 1
3460 read(iun, *,iostat=ier) xcan, xbcmode, xbctype, xnpred, (xpred(j), j = 1, numpredictorsbcif)
3461 if (ier /= 0) cycle
3462 bcmode(i) = xbcmode
3463 bctype(i) = xbctype
3464 npred(i) = xnpred
3465 do j = 1, numpredictorsbcif
3466 pred(i,j) = xpred(j)
3467 end do
3468 end do
3469 end if
3470 end if
3471 end if
3472 ! Non-GLOBAL: Read the entire file for channel specific values (all channels)
3473 ! ---------------------------------------------------------------------------------------------------------------------
3474 if (global_opt == 'NON') then
3475 ii = 1
3476 do
3477 read(iun,*,iostat=ier) can(ii), bcmode(ii), bctype(ii), npred(ii), (pred(ii,j), j = 1, numpredictorsbcif)
3478 if (ier < 0) exit
3479 if (ier > 0) then
3480 write(*,*) 'read_BCIF: Error reading file!'
3481 exitcode = ier
3482 return
3483 end if
3484 if (ii == 1) then
3485 if (can(ii) /= 0) then
3486 write(*,*) 'read_BCIF: Channel 0 global/default values not found!'
3487 exitcode = -1
3488 return
3489 end if
3490 end if
3491 ii = ii + 1
3492 end do
3493 if (ii - 2 < ncan) then
3494 write(*,*) 'read_BCIF: Number of channels in file is less than specified value (NCAN). Changing value of NCAN.'
3495 ncan = ii - 2
3496 end if
3497 if (ii > ncan + 2) then
3498 write(*,*) 'read_BCIF: ERROR -- Number of channels in file is greater than specified value (NCAN)!'
3499 exitcode = -1
3500 return
3501 end if
3502 end if
3503 ! ---------------------------------------------------------------------------------------------------------------------
3504 write(*,*) ' '
3505 write(*,*) 'read_BCIF: Bias correction information for each channel (from BCIF):'
3506 write(*,'(1X,A7,1X,I4)') instrum, ncan
3507 write(*,*) line
3508 do i = 1, ncan + 1
3509 chknp = count(pred(i,:) /= 'XX')
3510 if (chknp /= npred(i)) npred(i) = chknp
3511 if (npred(i) == 0 .and. bctype(i) == 'C') bctype(i) = 'F'
3512 write(*,'(I4,2(5X,A1),5X,I2,6(4X,A2))') can(i), bcmode(i), bctype(i), npred(i), (pred(i,j), j = 1, numpredictorsbcif)
3513 end do
3514 write(*,*) 'read_BCIF: exit '
3515
3516 ier = fclos(iun)
3517 exitcode = 0
3518
3519 end subroutine read_bcif
3520
3521 !-----------------------------------------
3522 ! read_coeff
3523 !-----------------------------------------
3524 subroutine read_coeff(sats, chans, fovbias, coeff, nsat, nchan, nfov, npred, cinstrum, coeff_file, ptypes, ndata)
3525 !
3526 !:Purpose: to read radiance bias correction coefficients file
3527 !
3528 implicit none
3529
3530 ! Arguments:
3531 character(len=10), intent(out) :: sats(:) ! dim(maxsat), satellite names 1
3532 integer, intent(out) :: chans(:,:) ! dim(maxsat, maxchan), channel numbers 2
3533 real(8), intent(out) :: fovbias(:,:,:)! dim(maxsat,maxchan,maxfov), bias as F(fov) 3
3534 real(8), intent(out) :: coeff(:,:,:) ! dim(maxsat,maxchan,maxpred+1) 4
3535 integer, intent(out) :: nsat !5
3536 integer, intent(out) :: nchan(:) ! dim(maxsat), number of channels 6
3537 integer, intent(out) :: nfov !7
3538 integer, intent(out) :: npred(:,:) ! dim(maxsat, maxchan), number of predictors !8
3539 character(len=7), intent(out) :: cinstrum ! string: instrument (e.g. AMSUB) 9
3540 character(len=*), intent(in) :: coeff_file ! 10
3541 character(len=2), intent(out) :: ptypes(:,:,:) ! dim(maxsat,maxchan,maxpred) 11
3542 integer, intent(out) :: ndata(:,:) ! dim(maxsat, maxchan), number of channels 12
3543
3544 ! Locals:
3545 character(len=8) :: sat
3546 character(len=120) :: line
3547 integer :: chan
3548 integer :: nbfov, nbpred, i, j, k, ier, istat, ii, nobs
3549 logical :: newsat, fileExists
3550 real :: dummy
3551 integer :: iun
3552 integer :: maxsat
3553 integer :: maxpred
3554
3555 ! sats(nsat) = satellite names
3556 ! chans(nsat,nchan(i)) = channel numbers of each channel of each satellite i
3557 ! npred(nsat,nchan(i)) = number of predictors for each channel of each satellite i
3558 ! fovbias(i,j,k) = bias for satellite i, channel j, FOV k k=1,nfov
3559 ! if FOV not considered for instrument, nfov = 1 and fovbias is global bias for channel
3560 ! coeff(i,j,1) = regression constant
3561 ! coeff(i,j,2), ..., coeff(i,j,npred(i,j)) = predictor coefficients
3562 ! nsat, nchan, nfov, cinstrum (output) are determined from file
3563 ! if returned nsat = 0, coeff_file was empty
3564
3565 inquire(file=trim(coeff_file), exist=fileExists)
3566 if (fileExists) then
3567 iun = 0
3568 ier = fnom(iun, coeff_file, 'FMT', 0)
3569 if (ier /= 0) then
3570 call utl_abort('read_coeff: ERROR - Problem opening the coefficient file! ' // trim(coeff_file))
3571 end if
3572
3573 write(*,*)
3574 write(*,*) 'read_coeff: Bias correction coefficient file open = ', coeff_file
3575
3576 end if
3577
3578 maxsat = size(sats)
3579 maxpred = size(ptypes, dim = 3)
3580
3581 coeff(:,:,:) = 0.0
3582 fovbias(:,:,:) = 0.0
3583 sats(:) = 'XXXXXXXX'
3584 cinstrum = 'XXXXXXX'
3585 chans(:,:) = 0
3586 npred(:,:) = 0
3587 nsat = 0
3588 nchan(:) = 0
3589 nfov = 0
3590 ptypes(:,:,:) = 'XX'
3591
3592 if (.not. fileExists) then
3593 write(*,*) 'read_coeff: Warning- File ' // trim(coeff_file) //'not there.'
3594 return
3595 end if
3596
3597 read(iun,*,iostat=istat)
3598
3599 if (istat /= 0) then
3600 write(*,*) 'read_coeff: Warning- File appears empty.'
3601 ier = fclos(iun)
3602 return
3603 end if
3604
3605 rewind(iun)
3606
3607 ii = 0
3608
3609 ! Loop over the satellites/channels in the file
3610
3611 do
3612 read(iun,'(A)',iostat=istat) line
3613 if (istat < 0) exit
3614 if (line(1:3) == 'SAT') then
3615 newsat = .true.
3616 read(line,'(T53,A8,1X,A7,1X,I6,1X,I8,1X,I2,1X,I3)',iostat=istat) sat, cinstrum, chan, nobs, nbpred, nbfov
3617 if (istat /= 0) then
3618 call utl_abort('read_coeff: ERROR - reading data from SATELLITE line in coeff file!')
3619 end if
3620 do i = 1, maxsat
3621 if (trim(sats(i)) == trim(sat)) then
3622 newsat = .false.
3623 ii = i
3624 end if
3625 end do
3626 if (newsat) then
3627 ii = ii + 1
3628 if (ii > maxsat) then
3629 call utl_abort('read_coeff: ERROR - max number of satellites exceeded in coeff file!')
3630 end if
3631 sats(ii) = sat
3632 if (ii > 1) nchan(ii - 1) = j
3633 j = 1
3634 else
3635 j = j + 1
3636 end if
3637 chans(ii,j) = chan
3638 npred(ii,j) = nbpred
3639 ndata(ii,j) = nobs
3640 if (nbpred > maxpred) then
3641 call utl_abort('read_coeff: ERROR - max number of predictors exceeded in coeff file!')
3642 end if
3643 read(iun,'(A)',iostat=istat) line
3644 if (line(1:3) /= 'PTY') then
3645 call utl_abort('read_coeff: ERROR - list of predictors is missing in coeff file!')
3646 end if
3647 if (nbpred > 0) then
3648 read(line,'(T8,6(1X,A2))', iostat = istat) (ptypes(ii,j,k), k = 1, nbpred)
3649 if (istat /= 0) then
3650 call utl_abort('read_coeff: ERROR - reading predictor types from PTYPES line in coeff file!')
3651 end if
3652 end if
3653 read(iun,*,iostat=istat) (fovbias(ii,j,k), k= 1, nbfov)
3654 if (istat /= 0) then
3655 call utl_abort('read_coeff: ERROR - reading fovbias in coeff file!')
3656 end if
3657 if (nbpred > 0) then
3658 read(iun,*,iostat=istat) (coeff(ii,j,k), k = 1, nbpred + 1)
3659 else
3660 read(iun,*,iostat=istat) dummy
3661 end if
3662 if (istat /= 0) then
3663 call utl_abort('read_coeff: ERROR - reading coeff in coeff file!')
3664 end if
3665 else
3666 exit
3667 end if
3668
3669 end do
3670
3671 if (ii == 0) then
3672 call utl_abort('read_coeff: ERROR - No data read from coeff file!')
3673 end if
3674
3675 nsat = ii
3676 nfov = nbfov
3677 nchan(ii) = j
3678
3679 write(*,*) ' '
3680 write(*,*) 'read_coeff: ------------- BIAS CORRECTION COEFFICIENT FILE ------------------ '
3681 write(*,*) ' '
3682 write(*,*) 'read_coeff: Number of satellites = ', nsat
3683 write(*,*) 'read_coeff: Number of FOV = ', nfov
3684 write(*,*) 'read_coeff: Max number of predictors = ', maxval(npred)
3685 write(*,*) ' '
3686 do i = 1, nsat
3687 write(*,*) 'read_coeff: Satellite = ' // sats(i)
3688 write(*,*) 'read_coeff: Number of channels = ', nchan(i)
3689 write(*,*) 'read_coeff: predictors, fovbias, coeff for each channel: '
3690 do j = 1, nchan(i)
3691 write(*,*) i, chans(i, j)
3692 if (npred(i, j) > 0) then
3693 write(*,'(6(1X,A2))') (ptypes(i,j,k), k = 1, npred(i,j))
3694 else
3695 write(*,'(A)') 'read_coeff: No predictors'
3696 end if
3697 write(*,*) (fovbias(i,j,k), k = 1, nfov)
3698 write(*,*) (coeff(i,j,k), k = 1, npred(i,j) + 1)
3699 end do
3700 end do
3701 write(*,*) 'read_coeff: exit'
3702
3703 ier = fclos(iun)
3704
3705 end subroutine read_coeff
3706
3707 !-----------------------------------------
3708 ! bcs_getChannelIndex
3709 !-----------------------------------------
3710 subroutine bcs_getChannelIndex(obsSpaceData, idsat, chanIndx,indexBody)
3711 !
3712 !:Purpose: to get the channel index (wrt bcif channels)
3713 !
3714 implicit none
3715
3716 ! Arguments:
3717 integer, intent(in) :: idsat
3718 integer, intent(in) :: indexBody
3719 integer, intent(out) :: chanIndx
3720 type(struct_obs), intent(inout) :: obsSpaceData
3721
3722 ! Locals:
3723 logical, save :: first =.true.
3724 integer :: ichan, isensor, indx
3725 integer, allocatable, save :: Index(:,:)
3726
3727 if (first) then
3728 allocate(Index(tvs_nsensors,tvs_maxChannelNumber))
3729 Index(:,:) = -1
3730 do isensor = 1, tvs_nsensors
3731 channels:do ichan = 1, tvs_maxChannelNumber
3732 indexes: do indx =1, bias(isensor)%numChannels
3733 if (ichan == bias(isensor)%chans(indx)%channelNum) then
3734 Index(isensor,ichan) = indx
3735 exit indexes
3736 end if
3737 end do indexes
3738 end do channels
3739 end do
3740 first = .false.
3741 end if
3742
3743 ichan = nint(obs_bodyElem_r(obsSpaceData, OBS_PPP, indexBody))
3744 ichan = max(0, min(ichan, tvs_maxChannelNumber + 1))
3745 ichan = ichan - tvs_channelOffset(idsat)
3746
3747 chanIndx = Index(idsat,ichan)
3748
3749 end subroutine bcs_getChannelIndex
3750
3751 !-----------------------------------------
3752 ! getObsFileName
3753 !-----------------------------------------
3754 function getObsFileName(codetype) result(fileName)
3755 !
3756 !:Purpose: Return the part of the observation file name associated
3757 ! with the type of observation it contains.
3758 !
3759 implicit none
3760
3761 ! Arguments:
3762 integer, intent(in) :: codeType
3763 ! Result:
3764 character(len=20) :: fileName
3765
3766 if (codtyp_get_name(codeType) == 'radianceclear') then
3767 fileName = 'csr'
3768 else if (codtyp_get_name(codeType) == 'mhs' .or. codtyp_get_name(codeType) == 'amsub') then
3769 fileName = 'to_amsub'
3770 else if (codtyp_get_name(codeType) == 'amsua') then
3771 fileName = 'to_amsua'
3772 else if (codtyp_get_name(codeType) == 'ssmi') then
3773 fileName = 'ssmis'
3774 else if (codtyp_get_name(codeType) == 'crisfsr') then
3775 fileName = 'cris'
3776 else
3777 fileName = codtyp_get_name(codeType)
3778 end if
3779
3780 end function getObsFileName
3781
3782 !-----------------------------------------
3783 ! getInitialIdObsData
3784 !-----------------------------------------
3785 subroutine getInitialIdObsData(obsSpaceData, obsFamily, idObs, idData, codeTypeList_opt)
3786 !
3787 !:Purpose: Compute initial value for idObs and idData that will ensure
3788 ! unique values over all mpi tasks
3789 !
3790 implicit none
3791
3792 ! Arguments:
3793 type(struct_obs), intent(inout) :: obsSpaceData
3794 character(len=*), intent(in) :: obsFamily
3795 integer, intent(out) :: idObs
3796 integer, intent(out) :: idData
3797 integer, optional, intent(in) :: codeTypeList_opt(:)
3798
3799 ! Locals:
3800 integer :: headerIndex, numHeader, numBody, codeType, ierr
3801 integer, allocatable :: allNumHeader(:), allNumBody(:)
3802
3803 numHeader = 0
3804 numBody = 0
3805 call obs_set_current_header_list(obsSpaceData, obsFamily)
3806 HEADERCOUNT: do
3807 headerIndex = obs_getHeaderIndex(obsSpaceData)
3808 if (headerIndex < 0) exit HEADERCOUNT
3809 if (present(codeTypeList_opt)) then
3810 codeType = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
3811 if (all(codeTypeList_opt(:) /= codeType)) cycle HEADERCOUNT
3812 end if
3813 numHeader = numHeader + 1
3814 numBody = numBody + obs_headElem_i(obsSpaceData, OBS_NLV, headerIndex)
3815 end do HEADERCOUNT
3816 allocate(allNumHeader(mmpi_nprocs))
3817 allocate(allNumBody(mmpi_nprocs))
3818 call rpn_comm_allgather(numHeader, 1, 'mpi_integer', &
3819 allNumHeader, 1, 'mpi_integer', 'GRID', ierr)
3820 call rpn_comm_allgather(numBody, 1, 'mpi_integer', &
3821 allNumBody, 1, 'mpi_integer', 'GRID', ierr)
3822 if (mmpi_myid > 0) then
3823 idObs = sum(allNumHeader(1:mmpi_myid))
3824 idData = sum(allNumBody(1:mmpi_myid))
3825 else
3826 idObs = 0
3827 idData = 0
3828 end if
3829 deallocate(allNumHeader)
3830 deallocate(allNumBody)
3831
3832 end subroutine getInitialIdObsData
3833
3834end module biasCorrectionSat_mod