bgckCSR_mod source

  1module bgckCSR_mod
  2  ! MODULE bgckCSR_mod (prefix='csrbg' category='1. High-level functionality')
  3  !
  4  !:Purpose: To perform CSR (clear-sky radiance from geostationary
  5  !          satellite platforms) data background check.
  6  !
  7  use midasMpi_mod
  8  use utilities_mod
  9  use obsSpaceData_mod
 10  use tovsNL_mod
 11  use obsErrors_mod
 12
 13  implicit none
 14  save
 15  private
 16
 17  real,    parameter :: csrbg_realMissing=-99.
 18  
 19  ! Public functions/subroutines
 20
 21  public :: csrbg_bgCheckCSR
 22  
 23  real, parameter :: csrbg_ompThreshold = 4.2
 24  integer, parameter :: maxNumsat  = 20     ! nb max de satellites
 25  integer, parameter :: maxNumchan = 15     ! nb max de canaux
 26
 27  ! namelist variables
 28  character (len=9)  :: burpSatName(maxNumSat)                   ! list of platform names to treat (BURP file station id)
 29  integer            :: satCloudCoverLimit(maxNumSat,maxNumchan) ! maximum limit of cloud cover (careful this is an integer!)
 30
 31  namelist /namcsr/burpSatName,satCloudCoverLimit
 32
 33contains
 34
 35  !----------------------------------------------------------------------------------------
 36  ! csrbg_init
 37  !----------------------------------------------------------------------------------------
 38  subroutine csrbg_init()
 39    !
 40    !:Purpose: This subroutine reads the namelist section NAMCSR
 41    !          for the module.
 42    implicit none
 43
 44    ! Locals:
 45    integer :: nulnam, ierr
 46    integer, external :: fnom, fclos
 47
 48    nulnam = 0
 49    ierr = fnom(nulnam, './flnml','FTN+SEQ+R/O', 0)
 50    read(nulnam, nml=namcsr, iostat=ierr)
 51    if (ierr /= 0) call utl_abort('csrbg_init: Error reading namelist')
 52    if (mmpi_myid == 0) write(*, nml=namcsr)
 53    ierr = fclos(nulnam)
 54
 55  end subroutine csrbg_init
 56  
 57  !----------------------------------------------------------------------------------------
 58  ! csrbg_bgCheckCSR
 59  !----------------------------------------------------------------------------------------
 60  subroutine csrbg_bgCheckCSR (obsSpaceData)
 61    !
 62    !: Purpose: Effectuer le controle que qualite sur les donnees CSR.  
 63    !           Modifier les marqueurs de donnees selon le type de rejet.
 64    !
 65    implicit none
 66
 67    ! Arguments:
 68    type(struct_obs),     intent(inout)  :: obsSpaceData           ! obspaceData Object
 69
 70    ! Locals:
 71    real   , allocatable  :: obsTb(:)            ! brightness temperature (btyp=9248/9264,ele=12163)
 72    real   , allocatable  :: ompTb(:)            ! OMP values
 73    real   , allocatable  :: satZenithAngle(:)   ! satellite zenith angle (btyp=3072,ele=7024)
 74    integer, allocatable  :: obsFlags(:)         ! data flags
 75    integer, allocatable  :: cloudAmount(:)      ! data flags
 76    integer, allocatable  :: obsChannels(:)      ! Tb Channels 
 77    integer, allocatable  :: obsDate(:)          ! date YYYYMMDD
 78    integer, allocatable  :: obsHour(:)          ! Hour HHMM
 79    integer               :: sensorIndex         ! find tvs_sensor index corresponding to current obs
 80    character(len=9)      :: burpFileSatId       ! Platform Name
 81    ! Data derived from elements read in obspace data
 82    logical, allocatable  :: maxAngleReached(:)  ! satellite angle exceed max angle at obs
 83    logical, allocatable  :: topographicData(:)  ! data flagged as topo data
 84    logical, allocatable  :: nonCorrectedData(:) ! data non corrected by bias corr
 85    logical, allocatable  :: isTbPresent(:)      ! non missing data
 86    logical, allocatable  :: isClearSky(:)       ! clear sky obs
 87    logical, allocatable  :: strayLight(:)       !
 88    logical, allocatable  :: goesMidi(:)         ! goes noon
 89    logical, allocatable  :: isToAssim(:)        ! is channel assimilable
 90    logical, allocatable  :: ompOutOfRange(:)        
 91    integer               :: categorieRejet(7)        
 92    integer               :: headerIndex 
 93    integer               :: codtyp
 94    logical               :: csrDataPresent
 95
 96    categorieRejet(:) = 0
 97    csrDataPresent = .false.
 98    call obs_set_current_header_list(obsSpaceData,'TO')
 99    HEADER0: do
100      headerIndex = obs_getHeaderIndex(obsSpaceData)
101      if (headerIndex < 0) exit HEADER0
102      codtyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
103      if (tvs_isIdBurpInst(codtyp,'radianceclear'  )) csrDataPresent = .true.
104    end do HEADER0
105
106    if ( .not. csrDataPresent ) then
107      write(*,*) 'WARNING: WILL NOT RUN csrbg_bgCheckCSR since no CSR Data'
108      return
109    end if
110
111    call utl_tmg_start(116,'--BgckCSR')
112    write(*,*) ' CSRBG QC PROGRAM STARTS ....'
113    ! Read Namelist
114    call csrbg_init()
115
116    call obs_set_current_header_list(obsSpaceData,'TO')
117    HEADER: do
118      headerIndex = obs_getHeaderIndex(obsSpaceData)
119      if (headerIndex < 0) exit HEADER
120      codtyp = obs_headElem_i(obsSpaceData, OBS_ITY, headerIndex)
121      if ( .not. tvs_isIdBurpInst(codtyp,'radianceclear') ) then 
122        write(*,*) 'WARNING: Observation with codtyp = ', codtyp, ' is not a CSR data'
123        cycle HEADER
124      end if
125
126      !###############################################################################
127      ! STEP 1) read obs from obsSpacedata to start QC                               !
128      !###############################################################################
129
130      call csrbg_readObsFromObsSpace(obsSpaceData, headerIndex, obsTb, ompTb, satZenithAngle, obsFlags, cloudAmount, &
131                                     obsChannels, sensorIndex, obsDate, obsHour, burpFileSatId, &
132                                     maxAngleReached, topographicData, nonCorrectedData, isTbPresent, &
133                                     isClearSky, strayLight, goesMidi, isToAssim, ompOutOfRange) 
134
135      !###############################################################################
136      ! STEP 2) Controle de qualite des CSR. Data QC flags (obsFlags) are modified here!
137      !###############################################################################
138
139      call csrbg_csrCheckQc(obsFlags, categorierejet, maxAngleReached, topographicData, &
140                            nonCorrectedData, isTbPresent, isClearSky, strayLight, goesMidi, isToAssim, &
141                            ompOutOfRange)
142
143      !###############################################################################
144      ! STEP 3) Update Flags and obs in obsspace data
145      !###############################################################################
146
147      call csrbg_updateObsSpaceAfterQc(obsSpaceData, obsFlags, headerIndex, sensorIndex)
148
149    end do HEADER 
150    write(*,*) "Nombre de donnees rejetees"
151    write(*,*) "Attention, une donnee peut etre rejetee pour plusieurs raisons"
152    write(*,*) "Maxangle, straylight ou goesmid    " , categorieRejet(1)
153    write(*,*) "Topographie                        " , categorieRejet(2)
154    write(*,*) "TB sans correction de biais        " , categorieRejet(3)
155    write(*,*) "Pas TB                             " , categorieRejet(4)
156    write(*,*) "std(O-P)*sigma trop grand          " , categorieRejet(5)
157    write(*,*) "canal non assimile                 " , categorieRejet(6)
158    write(*,*) "Ciel non clair                     " , categorieRejet(7)
159    write(*,*) "*******"
160
161    call utl_tmg_stop(116)
162
163  end subroutine csrbg_bgCheckCSR
164
165  !--------------------------------------------------------------------------
166  !  csrbg_readObsFromObsSpace
167  !--------------------------------------------------------------------------
168  subroutine csrbg_readObsFromObsSpace(obsSpaceData, headerIndex, obsTb, ompTb, satZenithAngle, obsFlags, cloudAmount, &
169                                       obsChannels, sensorIndex, obsDate, obsHour, burpFileSatId, &
170                                       maxAngleReached, topographicData, nonCorrectedData, isTbPresent, &
171                                       isClearSky, strayLight, goesMidi, isToAssim, ompOutOfRange)
172    !
173    !:Purpose:        copy headers and bodies from obsSpaceData object to arrays
174    !                 compute some parameters from the read variables
175    !
176    implicit None
177
178    ! Arguments:
179    integer ,             intent(in)    :: headerIndex         ! current header index
180    real   , allocatable, intent(out)   :: obsTb(:)            ! brightness temperature (btyp=9248/9264,ele=12163)
181    real   , allocatable, intent(out)   :: ompTb(:)            ! OMP values
182    real   , allocatable, intent(out)   :: satZenithAngle(:)   ! satellite zenith angle (btyp=3072,ele=7024)
183    integer, allocatable, intent(out)   :: obsFlags(:)         ! data flags
184    integer, allocatable, intent(out)   :: cloudAmount(:)      ! data flags
185    integer, allocatable, intent(out)   :: obsChannels(:)      ! Tb Channels 
186    integer, allocatable, intent(out)   :: obsDate(:)          ! date YYYYMMDD
187    integer, allocatable, intent(out)   :: obsHour(:)          ! Hour HHMM
188    integer,              intent(out)   :: sensorIndex         ! find tvs_sensor index corresponding to current obs
189    character(*),         intent(out)   :: burpFileSatId       ! Platform Name
190    type(struct_obs),     intent(inout) :: obsSpaceData        ! obspaceData Object
191    logical, allocatable, intent(out)   :: maxAngleReached(:)     ! satellite angle exceed max angle at obs
192    logical, allocatable, intent(out)   :: topographicData(:)  ! data flagged as topo data
193    logical, allocatable, intent(out)   :: nonCorrectedData(:) ! data non corrected by bias corr
194    logical, allocatable, intent(out)   :: isTbPresent(:)      ! non missing data
195    logical, allocatable, intent(out)   :: isClearSky(:)       ! clear sky obs
196    logical, allocatable, intent(out)   :: strayLight(:)       !
197    logical, allocatable, intent(out)   :: goesMidi(:)         ! goes noon
198    logical, allocatable, intent(out)   :: isToAssim(:)        ! is channel assimilable
199    logical, allocatable, intent(out)   :: ompOutOfRange(:)    ! 
200  
201    ! Locals:
202    integer                              :: bodyIndex
203    integer                              :: bodyIndexbeg
204    integer                              :: headerCompt
205    integer                              :: currentChannelNumber
206    integer                              :: channelIndex
207    integer                              :: actualnumChannel
208    integer                              :: numObsToProcess
209    integer                              :: iplatform
210    integer                              :: instrum
211    integer                              :: isat, iplatf
212    integer                              :: instr
213    integer                              :: mois
214    integer                              :: jour
215    integer                              :: heure
216    integer                              :: midnight
217    integer                              :: dataIndex
218    integer                              :: indexSat
219    logical                              :: sensorIndexFound
220    logical                              :: indexSatFound
221    real                                 :: errorThreshold
222
223    ! find tvs_sensor index corresponding to current obs
224
225    iplatf      = obs_headElem_i( obsSpaceData, OBS_SAT, headerIndex )
226    instr       = obs_headElem_i( obsSpaceData, OBS_INS, headerIndex )
227
228    call tvs_mapSat( iplatf, iplatform, isat )
229    call tvs_mapInstrum( instr, instrum )
230
231    sensorIndexFound = .false.
232    do sensorIndex =1, tvs_nsensors
233      if ( iplatform ==  tvs_platforms(sensorIndex)  .and. &
234           isat      ==  tvs_satellites(sensorIndex) .and. &
235           instrum   == tvs_instruments(sensorIndex)       ) then
236        sensorIndexFound = .true.
237        exit
238      end if
239    end do
240    
241    if ( .not. sensorIndexFound ) call utl_abort('csrbg_readObsFromObsSpace: sensor Index not found')
242
243    ! find actual Number of channels
244    actualNumChannel = tvs_coefs(sensorIndex)%coef%fmv_ori_nchn
245
246    headerCompt = 1
247    numObsToProcess = 1
248    ! Allocate Header elements
249    call utl_reAllocate(obsDate, numObsToProcess)
250    call utl_reAllocate(obsHour, numObsToProcess)
251    call utl_reAllocate(satZenithAngle, numObsToProcess)
252
253    ! Allocate Body elements
254    call utl_reAllocate(obsTb, numObsToProcess*actualNumChannel)
255    call utl_reAllocate(ompTb, numObsToProcess*actualNumChannel)
256    call utl_reAllocate(obsFlags, numObsToProcess*actualNumChannel)
257    call utl_reAllocate(cloudAmount, numObsToProcess*actualNumChannel)
258    call utl_reAllocate(obsChannels, numObsToProcess*actualNumChannel)
259
260    !initialization
261    obsTb(:) = csrbg_realMissing
262    ompTb(:) = csrbg_realMissing
263    obsChannels(:) = csrbg_realMissing
264    cloudAmount(:) = csrbg_realMissing
265    !
266    ! Header elements
267    !
268    burpFileSatId                      = obs_elem_c    ( obsSpaceData, 'STID' , headerIndex )
269    satZenithAngle(headerCompt)        = obs_headElem_r( obsSpaceData, OBS_SZA, headerIndex )
270    obsDate(headerCompt)               = obs_headElem_i( obsSpaceData, OBS_DAT, headerIndex )
271    obsHour(headerCompt)               = obs_headElem_i( obsSpaceData, OBS_ETM, headerIndex )
272    !
273    ! Body elements
274    !
275    bodyIndexbeg        = obs_headElem_i( obsSpaceData, OBS_RLN, headerIndex )
276
277    BODY: do bodyIndex =  bodyIndexbeg, bodyIndexbeg + obs_headElem_i( obsSpaceData, OBS_NLV, headerIndex ) - 1
278      currentChannelNumber = nint(obs_bodyElem_r( obsSpaceData,  OBS_PPP, bodyIndex )) - & 
279                             tvs_channelOffset(sensorIndex)
280      obsTb(currentChannelNumber)          = obs_bodyElem_r( obsSpaceData, OBS_VAR, bodyIndex )
281      ompTb(currentChannelNumber)          = obs_bodyElem_r( obsSpaceData, OBS_OMP, bodyIndex )
282      obsFlags(currentChannelNumber)       = obs_bodyElem_i( obsSpaceData, OBS_FLG, bodyIndex )
283      cloudAmount(currentChannelNumber)    = obs_bodyElem_i( obsSpaceData, OBS_CLA, bodyIndex)
284
285    end do BODY
286
287    do channelIndex=1, actualNumChannel
288      obsChannels(channelIndex)    = channelIndex+tvs_channelOffset(sensorIndex)
289    end do
290
291
292    ! Get index for satCloudCoverLimit for current current sat  
293    indexSatFound = .false.
294    do indexSat = 1, maxNumSat
295      if (trim(burpSatName(indexSat)) == trim(burpFileSatId)) then
296        indexSatFound = .true.
297        exit
298      end if 
299    end do
300    if ( .not. indexSatFound ) call utl_abort('csrbg_readObsFromObsSpace: Cloud Cover Limit Not & 
301                                               Found for ' // trim(burpFileSatId))
302    ! compute data for QC
303    call utl_reAllocate(topographicData, numObsToProcess)
304    call utl_reAllocate(maxAngleReached, numObsToProcess)
305    call utl_reAllocate(strayLight, numObsToProcess)
306    call utl_reAllocate(goesMidi, numObsToProcess)
307    call utl_reAllocate(isTbPresent, numObsToProcess*actualNumChannel)
308    call utl_reAllocate(nonCorrectedData, numObsToProcess*actualNumChannel)
309    call utl_reAllocate(isClearSky, numObsToProcess*actualNumChannel)
310    call utl_reAllocate(ompOutOfRange, numObsToProcess*actualNumChannel)
311    call utl_reAllocate(isToAssim, numObsToProcess*actualNumChannel)
312    
313    isTbPresent(:) = .false.
314    isClearSky(:) = .false.
315    nonCorrectedData = .false.
316    
317    do channelIndex=1, numObsToProcess*actualNumChannel
318      if (obsTb(channelIndex) /= csrbg_realMissing) isTbPresent(channelIndex) = .true.
319      if (cloudAmount(channelIndex) /= csrbg_realMissing .and. & 
320          cloudAmount(channelIndex) < satCloudCoverlimit(indexSat,channelIndex)) then
321        isClearSky(channelIndex) = .true.
322      end if 
323      if (.not. btest(obsFlags(channelIndex), 6)) nonCorrectedData(channelIndex) = .true.
324    end do
325
326    topographicData(:) = .false.
327    maxAngleReached(:) = .false.
328    do dataIndex=1, numObsToProcess
329      if (btest(obsFlags(dataIndex), 18)) topographicData(dataIndex) = .true.
330      if (satZenithAngle(dataIndex) > 15250) maxAngleReached(dataIndex) = .true.
331    end do
332
333    ! check O-P of Tb and set assim flag for each channel of satellite numsat using stat_iutilst
334    ! If channel not found in stats file, NO ASSIMILATE flag is set and O-P check is skipped
335    ompOutOfRange(:) = .false.
336    isToAssim(:) = .false.
337    do  channelIndex=1, numObsToProcess*actualNumChannel
338      if ( .not. oer_tovutil(obsChannels(channelIndex), sensorIndex) == 0) then
339        isToAssim(channelIndex) = .true.
340      end if
341      errorThreshold = oer_toverrst(obsChannels(channelIndex), sensorIndex)*csrbg_ompThreshold
342      if (abs(ompTb(channelIndex)) > errorThreshold) ompOutOfRange(channelIndex) = .true.
343    end do
344    
345    strayLight(:) = .false.
346    goesMidi(:) = .false.
347    do  dataIndex = 1, numObsToProcess
348      mois  = (obsDate(dataIndex)/100) - (obsDate(dataIndex)/10000)*100
349      jour  = (obsDate(dataIndex)/100) -  (obsDate(dataIndex)/100)*100
350      heure = obsHour(dataIndex)/100 
351      if (burpFileSatId == '^METSAT7') then
352        if ( heure == 21 ) straylight(dataIndex) = 1
353        if ( (heure == 20) .or. (heure == 22) ) then
354          if ( (jour + (mois-1)*30) > 20 .and. (jour + (mois-1)*30) < 135 ) straylight(dataIndex) = .true.
355          if ( (jour + (mois-1)*30) > 210 .and. (jour + (mois-1)*30) < 300 ) straylight(dataIndex) = .true.
356        end if
357      end if
358      if (burpFileSatId == '^GOES11' .or.  burpFileSatId == '^GOES15') midnight = 9
359      if (burpFileSatId == '^GOES13' .or.  burpFileSatId == '^GOES14') midnight = 5
360      if (burpFileSatId == '^GOES11' .or.  burpFileSatId == '^GOES15' .or. &
361          burpFileSatId == '^GOES13' .or.  burpFileSatId == '^GOES14') then
362        if ( (heure == (midnight - 1)) .or. (heure == midnight) ) goesMidi(dataIndex) = .true.
363      end if 
364    end do
365    
366  end subroutine csrbg_readObsFromObsSpace
367
368  !--------------------------------------------------------------------------
369  !  csrbg_csrCheckQc
370  !--------------------------------------------------------------------------
371  subroutine csrbg_csrCheckQc(obsFlags, categorieRejet, maxAngleReached, topographicData, &
372                              nonCorrectedData, isTbPresent, isClearSky, strayLight, goesMidi, isToAssim, &
373                              ompOutOfRange)
374    !
375    !:Purpose:        Modify obsFlags
376    !
377    implicit None
378
379    ! Arguments:
380    integer, intent(inout) :: obsFlags(:)         ! obs Flags to update
381    integer, intent(inout) :: categorieRejet(7)   ! the 7 categories of rejections
382    logical, intent(in)    :: maxAngleReached(:)  ! satellite angle exceed max angle at obs
383    logical, intent(in)    :: topographicData(:)  ! data flagged as topo data
384    logical, intent(in)    :: nonCorrectedData(:) ! data non corrected by bias corr
385    logical, intent(in)    :: isTbPresent(:)      ! non missing data
386    logical, intent(in)    :: isClearSky(:)       ! clear sky obs
387    logical, intent(in)    :: strayLight(:)       !
388    logical, intent(in)    :: goesMidi(:)         ! goes noon
389    logical, intent(in)    :: isToAssim(:)        ! is channel assimilable
390    logical, intent(in)    :: ompOutOfRange(:)    ! abs of omp greater than threshold 
391
392    ! Locals:
393    integer   :: currentChannelNumber
394    integer   :: channelIndex
395    integer   :: numObsToProcess
396    integer   :: numData
397    integer   :: dataIndex
398
399    numObsToProcess = 1
400    currentChannelNumber = size(obsFlags)/numObsToProcess
401
402    ! tests de controle de qualite sur les profils et canaux
403    numData = 0
404    do dataIndex = 1, numObsToProcess
405      do channelIndex = 1, currentChannelNumber
406        numData = numData+1
407        !Maxangle & Straylight & Goesmid : Bit 7 et 9 pour tous les canaux
408        if (maxAngleReached(dataIndex) == .true. .or. & 
409            strayLight(dataIndex)      == .true. .or. & 
410            goesMidi(dataIndex)        == .true. ) then 
411          obsFlags(numData) = ibset(obsFlags(numData),7) 
412          obsFlags(numData) = ibset(obsFlags(numData),9) 
413          categorieRejet(1) =  categorieRejet(1) + 1
414        end if
415
416        !Topo : bit 9 et 18 sont déjà là provenant du EnVar
417        if (topographicData(dataIndex) == .true.) then
418          obsFlags(numData) = ibset(obsFlags(numData),9) 
419          obsFlags(numData) = ibset(obsFlags(numData),18) 
420          categorieRejet(2) =  categorieRejet(2) + 1
421        end if 
422
423        !Pas corrige : bit 11
424        if (nonCorrectedData(numData) == .true.) then
425          obsFlags(numData) = ibset(obsFlags(numData),11) 
426          categorieRejet(3) =  categorieRejet(3) + 1
427        end if 
428
429        !Tbyela: bit  7 et 9 pour les canaux concernés
430        if (isTbPresent(numData) == .false.) then 
431          obsFlags(numData) = ibset(obsFlags(numData),7) 
432          obsFlags(numData) = ibset(obsFlags(numData),9) 
433          categorieRejet(4) =  categorieRejet(4) + 1
434        end if
435
436        !omp Out of range: Bit 9 et 16 pour les canaux concernés
437        if (ompOutOfRange(numData) == .true.) then 
438          obsFlags(numData) = ibset(obsFlags(numData),9)
439          obsFlags(numData) = ibset(obsFlags(numData),16)
440          categorieRejet(5) =  categorieRejet(5) + 1
441        end if
442
443        !Assim: Bit 11 pour les canaux concernés
444        if (isToAssim(numData) == .false.) then 
445          obsFlags(numData) = ibset(obsFlags(numData),11)
446          categorieRejet(6) =  categorieRejet(6) + 1
447        end if 
448
449        !Clearsky : Bit 7 & Bit 9
450        if (isClearSky(numData) == .false.) then 
451          obsFlags(numData) = ibset(obsFlags(numData),7)
452          obsFlags(numData) = ibset(obsFlags(numData),9)
453          categorieRejet(7) =  categorieRejet(7) + 1
454        end if  
455      end do
456    end do    
457
458  end subroutine csrbg_csrCheckQc
459
460  !--------------------------------------------------------------------------
461  ! csrbg_updateObsSpaceAfterQc
462  !--------------------------------------------------------------------------
463  subroutine csrbg_updateObsSpaceAfterQc(obsSpaceData, obsFlags, headerIndex, sensorIndex)
464    !
465    !:Purpose:      Update obspacedata variables (obstTB and obs flags) after QC
466    !
467    implicit None
468
469    ! Arguments:
470    type(struct_obs), intent(inout) :: obsSpaceData           ! obspaceData Object
471    integer,          intent(in)    :: obsFlags(:)            ! data flags
472    integer,          intent(in)    :: sensorIndex            ! sensor Index 
473    integer,          intent(in)    :: headerIndex            ! sensor Index 
474
475    ! Locals:
476    integer                         :: bodyIndex
477    integer                         :: bodyIndexbeg
478    integer                         :: currentChannelNumber
479
480    bodyIndexbeg        = obs_headElem_i( obsSpaceData, OBS_RLN, headerIndex )
481
482    BODY: do bodyIndex =  bodyIndexbeg, bodyIndexbeg + obs_headElem_i( obsSpaceData, OBS_NLV, headerIndex ) - 1
483      currentChannelNumber=nint(obs_bodyElem_r( obsSpaceData,  OBS_PPP, bodyIndex ))-tvs_channelOffset(sensorIndex)
484      call obs_bodySet_i(obsSpaceData, OBS_FLG, bodyIndex, obsFlags(currentChannelNumber))
485    end do BODY
486
487  end subroutine csrbg_updateObsSpaceAfterQc
488
489end module bgckCSR_mod