costFunction_mod sourceΒΆ

  1module costFunction_mod
  2  ! MODULE costFunction_mod, (prefix='cfn' category='5. Observation operators')
  3  !
  4  !:Purpose: To compute Jo term.
  5  !
  6  use midasMpi_mod
  7  use obsSpaceData_mod
  8  use rttov_const, only : inst_name, platform_name
  9  use tovsNL_mod
 10  use utilities_mod
 11  use obserrors_mod
 12  use codtyp_mod
 13
 14  implicit none
 15
 16  save
 17  private
 18
 19  ! public procedures
 20
 21  public :: cfn_calcJo, cfn_sumJo
 22
 23  integer,           allocatable :: channelNumberList(:,:)
 24  character(len=15), allocatable :: sensorNameList(:)
 25
 26contains
 27
 28  !--------------------------------------------------------------------------
 29  ! cfn_calcJo
 30  !--------------------------------------------------------------------------
 31  subroutine cfn_calcJo(lobsSpaceData)
 32    !
 33    !:Purpose: To compute JO contribution of each assimilated and diagnosed
 34    !          datum, and to store the result in OBS_JOBS
 35    implicit none
 36
 37    ! Arguments:
 38    type(struct_obs), intent(inout) :: lobsSpaceData
 39
 40    ! Locals:
 41    integer :: bodyIndex
 42
 43    !$OMP PARALLEL DO PRIVATE(bodyIndex)
 44    do bodyIndex=1,obs_numbody(lobsSpaceData)
 45
 46      if ( obs_bodyElem_i( lobsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated) then
 47        call obs_bodySet_r( lobsSpaceData, OBS_JOBS, bodyIndex, &
 48             ( obs_bodyElem_r( lobsSpaceData, OBS_WORK, bodyIndex ) &
 49             * obs_bodyElem_r( lobsSpaceData, OBS_WORK, bodyIndex ) &
 50             ) / 2.d0 )
 51      else
 52        call obs_bodySet_r(lobsSpaceData,OBS_JOBS,bodyIndex, 0.0d0)
 53      end if
 54
 55    end do
 56    !$OMP END PARALLEL DO
 57
 58  end subroutine cfn_calcJo
 59
 60  !--------------------------------------------------------------------------
 61  ! cfn_sumJo
 62  !--------------------------------------------------------------------------
 63  subroutine cfn_sumJo( lobsSpaceData, pjo, beSilent_opt )
 64    !
 65    !:Purpose: To compute the sum of Jo contributions saved in OBS_JOBS. Also,
 66    !          to compute contribution of each family of observation (for
 67    !          diagnostic purposes)
 68    implicit none
 69
 70    ! Arguments:
 71    type(struct_obs),    intent(in)  :: lobsSpaceData
 72    real(8),             intent(out) :: pjo ! Total observation cost function
 73    logical, optional,   intent(in) :: beSilent_opt
 74
 75    ! Locals:
 76    integer :: bodyIndex, tovsIndex, sensorIndex, headerIndex, bodyIndexBeg, bodyIndexEnd
 77    integer :: channelNumber, channelNumberIndexInListFound, channelIndex
 78    integer :: sensorIndexInList, sensorIndexInListFound
 79    logical :: beSilent
 80
 81    real(8) :: dljoraob, dljoairep, dljosatwind, dljoscat, dljosurfc, dljotov, dljosst, dljoice
 82    real(8) :: dljoprof, dljogpsro, dljogpsztd, dljochm, pjo_1, dljoaladin, dljohydro, dljoradar
 83    real(8) :: dljotov_sensors( tvs_nsensors )
 84    real(8) :: joTovsPerChannelSensor(tvs_maxNumberOfChannels,tvs_nsensors)
 85    character(len=15) :: lowerCaseName
 86
 87    logical :: printJoTovsPerChannelSensor
 88  
 89    real(8), allocatable :: joSSTInstrument(:)
 90    integer, allocatable :: nobsInstrument(:), nobsInstrumentGlob(:)
 91    integer :: SSTdatasetIndex, codeType, ierr
 92
 93    if ( present(beSilent_opt) ) then
 94      beSilent = beSilent_opt
 95    else
 96      beSilent = .false.
 97    end if
 98
 99    if (.not. allocated(channelNumberList)) then
100      allocate(channelNumberList(tvs_maxNumberOfChannels,tvs_nsensors))
101    end if
102    if (.not. allocated(sensorNameList)) then
103      allocate(sensorNameList(tvs_nsensors))
104    end if
105    
106    if(oer_getSSTdataParam_int('numberSSTDatasets') > 0) then
107      allocate(joSSTInstrument(oer_getSSTdataParam_int('numberSSTDatasets')))
108      allocate(nobsInstrument(oer_getSSTdataParam_int('numberSSTDatasets')))
109      allocate(nobsInstrumentGlob(oer_getSSTdataParam_int('numberSSTDatasets')))
110    end if
111
112    call readNameList
113    printJoTovsPerChannelSensor = .false.
114    if (any(sensorNameList(:) /= '') .and. any(channelNumberList(:,:) /= 0)) then
115      printJoTovsPerChannelSensor = .true.
116    end if
117
118    dljogpsztd = 0.d0
119    dljoraob = 0.d0
120    dljoairep = 0.d0
121    dljosatwind = 0.d0
122    dljosurfc = 0.d0
123    dljoscat = 0.d0
124    dljotov = 0.d0
125    dljogpsro = 0.d0
126    dljoprof = 0.d0
127    dljochm = 0.d0
128    dljosst = 0.0d0
129    dljoaladin = 0.d0
130    dljoice = 0.0d0
131    dljotov_sensors(:) = 0.d0
132    joTovsPerChannelSensor(:,:) = 0.0d0
133    dljohydro = 0.0d0
134    dljoradar = 0.0d0
135    joSSTInstrument(:) = 0.0d0
136    nobsInstrumentGlob(:) = 0
137    nobsInstrument(:) = 0
138
139    pjo = 0.0d0
140
141    do bodyIndex = 1, obs_numbody(lobsSpaceData)
142
143      pjo_1 = obs_bodyElem_r(lobsSpaceData, OBS_JOBS, bodyIndex)
144
145      ! total observation cost function
146      pjo   = pjo + pjo_1
147
148      ! subcomponents of observation cost function (diagnostic only)
149      select case(obs_getFamily(lobsSpaceData, bodyIndex_opt = bodyIndex))
150      case('UA')
151        dljoraob    = dljoraob    + pjo_1
152      case('AI')
153        dljoairep   = dljoairep   + pjo_1
154      case('SW')
155        dljosatwind = dljosatwind + pjo_1
156      case('SF')
157        dljosurfc   = dljosurfc   + pjo_1
158      case('SC')
159        dljoscat    = dljoscat    + pjo_1
160      case('TO')
161        dljotov     = dljotov     + pjo_1
162      case('RO')
163        dljogpsro   = dljogpsro   + pjo_1
164      case('PR')
165        dljoprof    = dljoprof    + pjo_1
166      case('GP')
167        dljogpsztd  = dljogpsztd  + pjo_1
168      case('CH')
169        dljochm     = dljochm     + pjo_1
170      case('TM')
171        dljosst     = dljosst     + pjo_1
172      case('AL')
173        dljoaladin  = dljoaladin  + pjo_1
174      case('GL')
175        dljoice     = dljoice     + pjo_1
176      case('HY')
177        dljohydro   = dljohydro   + pjo_1
178      case('RA')
179        dljoradar   = dljoradar   + pjo_1
180      end select
181    enddo
182
183    do tovsIndex = 1, tvs_nobtov
184      headerIndex = tvs_headerIndex( tovsIndex )
185      if ( headerIndex > 0 ) then
186        bodyIndexBeg = obs_headElem_i(lobsSpaceData, OBS_RLN, headerIndex)
187        bodyIndexEnd = obs_headElem_i(lobsSpaceData, OBS_NLV, headerIndex) + bodyIndexBeg - 1
188        sensorIndex = tvs_lsensor (tovsIndex)
189
190        sensorIndexInListFound = 0
191        if ( printJoTovsPerChannelSensor ) then
192          loopSensor1: do sensorIndexInList = 1, tvs_nsensors
193            call up2low(sensorNameList(sensorIndexInList),lowerCaseName)
194
195            if ( trim(lowerCaseName) == trim(inst_name(tvs_instruments(sensorIndex))) ) then
196              sensorIndexInListFound = sensorIndexInList
197              exit loopSensor1
198            end if
199
200          end do loopSensor1
201        end if
202
203        do bodyIndex = bodyIndexBeg, bodyIndexEnd
204          pjo_1 = obs_bodyElem_r(lobsSpaceData, OBS_JOBS, bodyIndex)
205          dljotov_sensors(sensorIndex) =  dljotov_sensors(sensorIndex) + pjo_1
206
207          if ( printJoTovsPerChannelSensor .and. &
208               sensorIndexInListFound > 0 ) then
209            call tvs_getChannelNumIndexFromPPP( lobsSpaceData, headerIndex, bodyIndex, &
210                                                channelNumber, channelIndex )
211            channelNumberIndexInListFound = utl_findloc(channelNumberList(:,sensorIndexInListFound), &
212                                                        channelNumber)
213
214            if ( channelNumberIndexInListFound > 0 ) then
215              joTovsPerChannelSensor(channelNumberIndexInListFound,sensorIndexInListFound) = &
216                        joTovsPerChannelSensor(channelNumberIndexInListFound,sensorIndexInListFound) + &
217                        pjo_1
218            end if
219
220          end if
221
222        end do
223      end if
224    end do
225
226    if(oer_getSSTdataParam_int('numberSSTDatasets') > 0) then
227      do headerIndex = 1, obs_numheader(lobsSpaceData)
228        codeType     = obs_headElem_i(lobsSpaceData, OBS_ITY, headerIndex)
229        bodyIndexBeg = obs_headElem_i(lobsSpaceData, OBS_RLN, headerIndex)
230        bodyIndexEnd = obs_headElem_i(lobsSpaceData, OBS_NLV, headerIndex) + bodyIndexBeg - 1
231        do bodyIndex = bodyIndexBeg, bodyIndexEnd
232          pjo_1 = obs_bodyElem_r(lobsSpaceData, OBS_JOBS, bodyIndex)
233          dataset_loop: do SSTdatasetIndex = 1, oer_getSSTdataParam_int('numberSSTDatasets')
234            if (codeType == oer_getSSTdataParam_int('codeType', SSTdatasetIndex) .and. codeType /= codtyp_get_codtyp('satob')) then
235              joSSTInstrument(SSTdatasetIndex) = joSSTInstrument(SSTdatasetIndex) + pjo_1
236              nobsInstrument(SSTdatasetIndex) = nobsInstrument(SSTdatasetIndex) + 1
237              exit dataset_loop
238            else
239              if (obs_elem_c(lobsSpaceData, 'STID', headerIndex) == oer_getSSTdataParam_char('sensor', SSTdatasetIndex)) then
240                joSSTInstrument(SSTdatasetIndex) = joSSTInstrument(SSTdatasetIndex) + pjo_1
241                nobsInstrument(SSTdatasetIndex) = nobsInstrument(SSTdatasetIndex) + 1
242                exit dataset_loop
243              end if
244            end if
245          end do dataset_loop
246        end do
247      end do
248    end if
249
250    call mmpi_allreduce_sumreal8scalar( pjo, "GRID" )
251    call mmpi_allreduce_sumreal8scalar( dljoraob, "GRID" )
252    call mmpi_allreduce_sumreal8scalar( dljoairep, "GRID" )
253    call mmpi_allreduce_sumreal8scalar( dljosatwind, "GRID" )
254    call mmpi_allreduce_sumreal8scalar( dljosurfc, "GRID" )
255    call mmpi_allreduce_sumreal8scalar( dljoscat, "GRID" )
256    call mmpi_allreduce_sumreal8scalar( dljotov, "GRID" )
257    call mmpi_allreduce_sumreal8scalar( dljogpsro, "GRID" )
258    call mmpi_allreduce_sumreal8scalar( dljoprof, "GRID" )
259    call mmpi_allreduce_sumreal8scalar( dljogpsztd, "GRID" )
260    call mmpi_allreduce_sumreal8scalar( dljochm, "GRID" )
261    call mmpi_allreduce_sumreal8scalar( dljosst, "GRID" )
262    call mmpi_allreduce_sumreal8scalar( dljoaladin,"GRID")
263    call mmpi_allreduce_sumreal8scalar( dljoice, "GRID" )
264    call mmpi_allreduce_sumreal8scalar( dljohydro, "GRID" )
265    call mmpi_allreduce_sumreal8scalar( dljoradar, "GRID" )
266    do sensorIndex = 1, tvs_nsensors
267      call mmpi_allreduce_sumreal8scalar(dljotov_sensors(sensorIndex), "GRID")
268    end do
269    if (printJoTovsPerChannelSensor) then
270      loopSensor2: do sensorIndex = 1, tvs_nsensors
271        if (trim(sensorNameList(sensorIndex)) == '') cycle loopSensor2
272
273        call mmpi_allreduce_sumR8_1d(joTovsPerChannelSensor(:,sensorIndex), "GRID")
274      end do loopSensor2
275    end if
276
277    ! SST data per instrument
278    do SSTdatasetIndex = 1, oer_getSSTdataParam_int('numberSSTDatasets')
279      call mmpi_allreduce_sumreal8scalar(joSSTInstrument(SSTdatasetIndex), "grid")
280      call rpn_comm_allreduce(nobsInstrument(SSTdatasetIndex), nobsInstrumentGlob(SSTdatasetIndex), &
281                              1, "mpi_integer", "mpi_sum", "grid", ierr)
282    end do
283
284    if ( mmpi_myid == 0 .and. .not. beSilent ) then
285      write(*,'(a15,f30.17)') 'Jo(UA)   = ', dljoraob
286      write(*,'(a15,f30.17)') 'Jo(AI)   = ', dljoairep
287      write(*,'(a15,f30.17)') 'Jo(SF)   = ', dljosurfc
288      write(*,'(a15,f30.17)') 'Jo(SC)   = ', dljoscat
289      write(*,'(a15,f30.17)') 'Jo(TO)   = ', dljotov
290      write(*,'(a15,f30.17)') 'Jo(SW)   = ', dljosatwind
291      write(*,'(a15,f30.17)') 'Jo(PR)   = ', dljoprof
292      write(*,'(a15,f30.17)') 'Jo(RO)   = ', dljogpsro
293      write(*,'(a15,f30.17)') 'Jo(GP)   = ', dljogpsztd
294      write(*,'(a15,f30.17)') 'Jo(CH)   = ', dljochm
295      write(*,'(a15,f30.17)') 'Jo(TM)   = ', dljosst
296      write(*,'(a15,f30.17)') 'Jo(AL)   = ', dljoaladin
297      write(*,'(a15,f30.17)') 'Jo(GL)   = ', dljoice
298      write(*,'(a15,f30.17)') 'Jo(HY)   = ', dljohydro
299      write(*,'(a15,f30.17)') 'Jo(RA)   = ', dljoradar
300      write(*,*) ' '
301      if ( tvs_nsensors > 0 ) then
302        write(*,'(1x,a)') 'For TOVS decomposition by sensor:'
303        write(*,'(1x,a)') '#  plt sat ins    Jo'
304        do sensorIndex = 1, tvs_nsensors
305          write(*,'(i2,1x,a,1x,a,1x,i2,1x,f30.17)') sensorIndex, inst_name(tvs_instruments(sensorIndex)), &
306                                                    platform_name(tvs_platforms(sensorIndex)), &
307                                                    tvs_satellites(sensorIndex), &
308                                                    dljotov_sensors(sensorIndex)
309        end do
310        write(*,*) ' '
311      end if
312
313      ! print per channel information
314      if ( tvs_nsensors > 0 .and. printJoTovsPerChannelSensor ) then
315        write(*,'(1x,a)') 'For TOVS decomposition by sensor/channel:'
316        write(*,'(1x,a)') 'index  sensorName  channel  Jo'
317        loopSensor3: do sensorIndex = 1, tvs_nsensors
318        if ( trim(sensorNameList(sensorIndex)) == '' ) cycle loopSensor3
319
320          loopChannel: do channelIndex = 1, tvs_maxNumberOfChannels
321            if ( channelNumberList(channelIndex,sensorIndex) == 0 ) cycle loopChannel
322
323            write(*,'(i2,1x,a,1x,i4,1x,f30.17)') sensorIndex, &
324                                                 sensorNameList(sensorIndex), &
325                                                 channelNumberList(channelIndex,sensorIndex), &
326                                                 joTovsPerChannelSensor(channelIndex,sensorIndex)
327          end do loopChannel
328
329        end do loopSensor3
330        write(*,*) ' '
331      end if
332
333      ! print SST data per instrument
334      if(oer_getSSTdataParam_int('numberSSTDatasets') > 0) then
335        write(*,*) 'cfn_sumJo: SST data by data type:'
336        write(*,'(a5,a15,a10,a30,a10, a15)') 'index', ' instrument', ' sensor', ' Jo', ' nobs', ' Jo/nobs'
337        do SSTdatasetIndex = 1, oer_getSSTdataParam_int('numberSSTDatasets')
338          if (nobsInstrumentGlob(SSTdatasetIndex) > 0) then
339            write(*,'(i5,a15,a10,f30.17,i15,f10.5)') SSTdatasetIndex, &
340                                                     oer_getSSTdataParam_char('instrument', SSTdatasetIndex),&
341                                                     oer_getSSTdataParam_char('sensor', SSTdatasetIndex), &
342                                                     joSSTInstrument(SSTdatasetIndex), &
343                                                     nobsInstrumentGlob(SSTdatasetIndex),&
344                                                     joSSTInstrument(SSTdatasetIndex) / &
345                                                     real(nobsInstrumentGlob(SSTdatasetIndex))
346          end if    
347        end do
348      end if
349
350    end if
351    
352    if(oer_getSSTdataParam_int('numberSSTDatasets') > 0) then
353      deallocate(joSSTInstrument)
354      deallocate(nobsInstrument)
355      deallocate(nobsInstrumentGlob)
356    end if
357
358  end subroutine cfn_sumJo
359
360  !--------------------------------------------------------------------------
361  ! readNameList
362  !--------------------------------------------------------------------------
363  subroutine readNameList
364    !
365    !:Purpose: Reading NAMCFN namelist by any subroutines in costfunction_mod module.
366    !
367    implicit none
368
369    ! Locals:
370    integer :: nulnam, ierr
371    integer, external :: fnom, fclos
372    logical, save :: nmlAlreadyRead = .false.
373    NAMELIST /NAMCFN/ sensorNameList, channelNumberList
374
375    if ( .not. nmlAlreadyRead ) then
376      nmlAlreadyRead = .true.
377
378      !- Setting default values
379      sensorNameList(:) = ''
380      channelNumberList(:,:) = 0
381
382      if ( .not. utl_isNamelistPresent('NAMCFN','./flnml') ) then
383        if ( mmpi_myid == 0 ) then
384          write(*,*) 'NAMCFN is missing in the namelist. The default values will be taken.'
385        end if
386
387      else
388        ! Reading the namelist
389        nulnam = 0
390        ierr = fnom(nulnam, './flnml', 'FTN+SEQ+R/O', 0)
391        read(nulnam, nml=namcfn, iostat=ierr)
392        if ( ierr /= 0) call utl_abort('costfunction_mod: Error reading namelist')
393        ierr = fclos(nulnam)
394
395        call sortChannelNumbersInNml
396      end if
397      if ( mmpi_myid == 0 ) write(*,nml=namcfn)
398    end if
399
400  end subroutine readNameList
401
402  !--------------------------------------------------------------------------
403  ! sortChannelNumbersInNml
404  !--------------------------------------------------------------------------
405  subroutine sortChannelNumbersInNml
406    !
407    !:Purpose: Sort channelNumbers in NAMCFN namelist. This involves removing
408    !          the duplicates and combine channelNumbers of same sensor
409    !          prescribed on different lines.
410    !
411    implicit none
412
413    ! Locals:
414    integer :: channelIndex
415    integer :: channelIndex1, channelIndex2
416    integer :: sensorIndexInList, sensorIndexInList1, sensorIndexInList2
417
418    character(len=15) :: sensorName1LowerCase, sensorName2LowerCase
419
420    if ( mmpi_myid == 0 ) then
421      write(*,*) 'costfunction_mod: sortChannelNumbersInNml START'
422    end if
423
424    ! set duplicate channelNumber for each sensor to zero
425    loopSensor3: do sensorIndexInList = 1, tvs_nsensors
426      if ( trim(sensorNameList(sensorIndexInList)) == '' ) cycle loopSensor3
427
428      loopChannel2: do channelIndex = tvs_maxNumberOfChannels, 2, -1
429        if ( channelNumberList(channelIndex,sensorIndexInList) == 0 ) cycle loopChannel2
430
431        if ( any(channelNumberList(1:channelIndex-1,sensorIndexInList) == &
432                 channelNumberList(channelIndex    ,sensorIndexInList)) ) then
433          channelNumberList(channelIndex,sensorIndexInList) = 0
434        end if
435      end do loopChannel2
436    end do loopSensor3
437
438    ! remove later duplicates of sensor/channel pairs
439    loopSensor4: do sensorIndexInList1 = 1, tvs_nsensors-1
440      if ( trim(sensorNameList(sensorIndexInList1)) == '' ) cycle loopSensor4
441
442      call up2low(sensorNameList(sensorIndexInList1),sensorName1LowerCase)
443
444      loopSensor5: do sensorIndexInList2 = sensorIndexInList1+1, tvs_nsensors
445        if ( trim(sensorNameList(sensorIndexInList2)) == '' ) cycle loopSensor5
446
447        call up2low(sensorNameList(sensorIndexInList2),sensorName2LowerCase)
448
449        if ( trim(sensorName2LowerCase) == trim(sensorName1LowerCase) ) then
450          loopChannel3: do channelIndex2 = 1, tvs_maxNumberOfChannels
451            if ( channelNumberList(channelIndex2,sensorIndexInList2) == 0 ) cycle loopChannel3
452
453            if ( any(channelNumberList(:           ,sensorIndexInList1) == &
454                     channelNumberList(channelIndex2,sensorIndexInList2)) ) then
455              ! set second occurance of channelNumber to zero
456              channelNumberList(channelIndex2,sensorIndexInList2) = 0
457            else
458
459              ! replace the first zero channelNumber of first sensor with new non-zero channelNumber
460              do channelIndex1 = 1, tvs_maxNumberOfChannels
461                if ( channelNumberList(channelIndex1,sensorIndexInList1) == 0 ) then
462                  channelNumberList(channelIndex1,sensorIndexInList1) = &
463                        channelNumberList(channelIndex2,sensorIndexInList2)
464                  channelNumberList(channelIndex2,sensorIndexInList2) = 0
465                  exit
466                end if
467              end do
468
469            end if
470
471          end do loopChannel3
472        end if
473      end do loopSensor5
474    end do loopSensor4
475
476    ! if all entries for a sensor are zero, remove the sensor from namelist.
477    ! otherwise sort in ascending order
478    loopSensor6: do sensorIndexInList = 1, tvs_nsensors
479      if ( trim(sensorNameList(sensorIndexInList)) == '' ) cycle loopSensor6
480
481      if ( all(channelNumberList(:,sensorIndexInList) == 0) ) then
482        sensorNameList(sensorIndexInList) = ''
483      else
484        call isort(channelNumberList(:,sensorIndexInList),tvs_maxNumberOfChannels)
485      end if
486    end do loopSensor6
487
488    if ( mmpi_myid == 0 ) then
489      write(*,*) 'costfunction_mod: sortChannelNumbersInNml END'
490    end if
491
492  end subroutine sortChannelNumbersInNml
493
494end module costFunction_mod