oceanObservations_mod sourceΒΆ

  1module oceanObservations_mod
  2  ! MODULE oceanObservations_mod (prefix='oobs' category='1. High-level functionality')
  3  !
  4  !:Purpose: storage for ocean observations related subroutines.
  5  !
  6  use midasMpi_mod
  7  use utilities_mod
  8  use obsSpaceData_mod
  9  use codtyp_mod
 10  use gridStateVector_mod
 11  use gridStateVectorFileIO_mod
 12  use horizontalCoord_mod
 13  use verticalCoord_mod
 14  use oceanMask_mod
 15  use timeCoord_mod
 16  use codePrecision_mod  
 17  use sqliteRead_mod
 18  use bufr_mod
 19  
 20  implicit none
 21
 22  save
 23  private
 24
 25  ! Public functions/subroutines
 26  public :: oobs_pseudoSST
 27 
 28  ! External functions
 29  integer, external :: fnom, fclos  
 30
 31  ! mpi topology
 32  integer :: myLatBeg, myLatEnd
 33  integer :: myLonBeg, myLonEnd
 34  integer :: latPerPE, latPerPEmax, lonPerPE, lonPerPEmax
 35
 36  contains
 37
 38  !----------------------------------------------------------------------------------------
 39  ! oobs_pseudoSST
 40  !----------------------------------------------------------------------------------------
 41  subroutine oobs_pseudoSST(hco, vco, iceFractionThreshold, outputSST, outputFreshWaterST, &
 42                            iceThinning, outputFileName, seaWaterThreshold)
 43    !
 44    !:Purpose: to generate pseudo SST data  
 45    !
 46    implicit none
 47    
 48    ! Arguments:
 49    type(struct_hco), pointer , intent(inout) :: hco                  ! horizontal grid structure
 50    type(struct_vco), pointer , intent(in)    :: vco                  ! vertical grid structure
 51    real(4)                   , intent(in)    :: iceFractionThreshold ! consider no ice condition below this threshold
 52    real(4)                   , intent(in)    :: outputSST            ! output SST value for pseudo observations
 53    real(4)                   , intent(in)    :: outputFreshWaterST   ! output fresh water surface temperature for pseudo obs
 54    integer                   , intent(in)    :: iceThinning          ! generate pseudo obs in every 'iceThinning' points   
 55    character(len=*)          , intent(in)    :: outputFileName    
 56    real(4)                   , intent(in)    :: seaWaterThreshold    ! to distinguish inland water from sea water  
 57    
 58    ! Locals:
 59    type(struct_gsv)            :: stateVector_ice, stateVector_seaWater
 60    real(4), pointer            :: seaIce_ptr(:, :, :), seaWater_ptr(:, :, :)
 61    type(struct_ocm)            :: oceanMask
 62    integer                     :: numberIceCoveredPoints, lonIndex, latIndex, dateStamp, inlandWaterPoints
 63    integer                     :: datePrint, timePrint, imode, seaWaterPoints
 64    integer                     :: randomSeed, newDate, ierr 
 65    integer, allocatable        :: iceDomainIndexesAux(:), iceDomainIndexes(:)
 66    real(4), allocatable        :: seaWaterFractionAux(:), iceLonsAux(:), iceLatsAux(:)  
 67    real(4), allocatable        :: seaWaterFraction(:), iceLons(:), iceLats(:)
 68    type(struct_obs)            :: obsData   
 69    
 70    ! get mpi topology
 71    call mmpi_setup_lonbands(hco%ni, lonPerPE, lonPerPEmax, myLonBeg, myLonEnd)
 72    call mmpi_setup_latbands(hco%nj, latPerPE, latPerPEmax, myLatBeg, myLatEnd)
 73
 74    ! get latest sea-ice analysis
 75    call gsv_allocate(stateVector_ice, 1, hco, vco, dataKind_opt = 4, &
 76                      datestamp_opt = -1, mpi_local_opt = .false., varNames_opt = (/'LG'/))
 77    call gio_readFromFile(stateVector_ice, './seaice_analysis', ' ','A', &
 78                          unitConversion_opt=.false., containsFullField_opt=.true.)
 79    call gsv_getField(stateVector_ice, seaIce_ptr)
 80
 81    ! read sea water fraction
 82    call gsv_allocate(stateVector_seaWater, 1, hco, vco, dataKind_opt = 4, &
 83                      datestamp_opt = -1, mpi_local_opt = .false., varNames_opt = (/'VF'/))
 84    call gio_readFromFile(stateVector_seaWater, './seaice_analysis', ' ','A', &
 85                          unitConversion_opt=.false., containsFullField_opt=.true.)
 86    call gsv_getField(stateVector_seaWater, seaWater_ptr)
 87
 88    ! Get land mask from analysisgrid file (1=water, 0=land)
 89    call ocm_readMaskFromFile(oceanMask, hco, vco, './analysisgrid')
 90
 91    allocate(iceDomainIndexesAux((myLonEnd - myLonBeg + 1) * (myLatEnd - myLatBeg + 1)))
 92    allocate(iceLonsAux((myLonEnd - myLonBeg + 1) * (myLatEnd - myLatBeg + 1)))
 93    allocate(iceLatsAux((myLonEnd - myLonBeg + 1) * (myLatEnd - myLatBeg + 1)))
 94    allocate(seaWaterFractionAux((myLonEnd - myLonBeg + 1) * (myLatEnd - myLatBeg + 1)))
 95    
 96    numberIceCoveredPoints = 0
 97    inlandWaterPoints = 0
 98    seaWaterPoints = 0
 99    
100    do lonIndex = myLonBeg, myLonEnd 
101      do latIndex = myLatBeg, myLatEnd
102        if (oceanMask%mask(lonIndex, latIndex, 1)) then
103          if (seaice_ptr(lonIndex, latIndex, 1) > iceFractionThreshold) then
104	  
105            numberIceCoveredPoints = numberIceCoveredPoints + 1
106	    iceDomainIndexesAux(numberIceCoveredPoints) = numberIceCoveredPoints
107	    seaWaterFractionAux(numberIceCoveredPoints) = seaWater_ptr(lonIndex, latIndex, 1)
108
109	    if(seaWater_ptr(lonIndex, latIndex, 1) <= seaWaterThreshold) then
110	      inlandWaterPoints = inlandWaterPoints + 1
111	    else
112	      seaWaterPoints = seaWaterPoints + 1
113	    end if  	      
114	  
115	    iceLonsAux(numberIceCoveredPoints) = hco%lon2d_4 (lonIndex, latIndex)
116	    iceLatsAux(numberIceCoveredPoints) = hco%lat2d_4 (lonIndex, latIndex)	
117          
118	  end if
119        end if
120      end do
121    end do
122    call ocm_deallocate(oceanMask)
123    call gsv_deallocate(stateVector_ice)
124    call gsv_deallocate(stateVector_seaWater)
125    write(*,*) 'oobs_pseudoSST: ', numberIceCoveredPoints, ' ice-covered points found'
126    write(*,*) 'oobs_pseudoSST: where ', inlandWaterPoints, ' are inland water points'
127    write(*,*) 'oobs_pseudoSST: ', seaWaterPoints, ' sea water points found'
128
129    if (numberIceCoveredPoints > 0) then
130      allocate(iceDomainIndexes(1:numberIceCoveredPoints))
131      iceDomainIndexes(:) = iceDomainIndexesAux(1:numberIceCoveredPoints)
132      allocate(seaWaterFraction(1:numberIceCoveredPoints))      
133      seaWaterFraction(:) = seaWaterFractionAux(1:numberIceCoveredPoints)
134      allocate(iceLons(1:numberIceCoveredPoints))
135      allocate(iceLats(1:numberIceCoveredPoints))
136      iceLons(:) = iceLonsAux(1:numberIceCoveredPoints)
137      iceLats(:) = iceLatsAux(1:numberIceCoveredPoints)
138    end if  
139    deallocate(iceLonsAux)
140    deallocate(iceLatsAux)
141    deallocate(iceDomainIndexesAux)
142    deallocate(seaWaterFractionAux)
143        
144    dateStamp = tim_getDatestampFromFile('./seaice_analysis', varNameForDate_opt = 'LG')
145    write(*,*) 'oobs_pseudoSST: datestamp: ', dateStamp 
146    ! compute random seed from the date for randomly forming sea-ice subdomain
147    imode = -3 ! stamp to printable date and time: YYYYMMDD, HHMMSShh
148    ierr = newdate(dateStamp, datePrint, timePrint, imode)
149    timePrint = timePrint / 1000000
150    datePrint =  datePrint * 100 + timePrint
151    
152    ! Remove the century, keeping 2 digits of the year
153    randomSeed = datePrint - 100000000 * (datePrint / 100000000)
154    write(*,*) 'oobs_pseudoSST: datePrint, timePrint: ', datePrint, timePrint 
155
156    if (numberIceCoveredPoints > 0) then
157
158      call utl_randomOrderInt(iceDomainIndexes, randomSeed)
159      write(*,*) 'oobs_pseudoSST: seed for random shuffle of sea-ice points: ', randomSeed
160    
161      call oobs_computeObsData(obsData, iceDomainIndexes, iceLons, iceLats, &
162                               iceThinning, outputSST, outputFreshWaterST, &
163                               outputFileName, datePrint, timePrint, &
164                               seaWaterFraction, seaWaterThreshold, inlandWaterPoints)
165    else 
166    
167      call obs_initialize(obsData, numHeader_max_opt = 0, numBody_max_opt = 0, mpi_local_opt = .true.)
168      call sqlr_writeEmptyPseudoSSTobsFile(obsData, 'SF', outputFileName)   
169
170    end if
171
172    if (numberIceCoveredPoints > 0) then
173      deallocate(iceLons)
174      deallocate(iceLats)
175      deallocate(iceDomainIndexes)
176      deallocate(seaWaterFraction)
177    end if  
178    
179    write(*,*) 'oobs_pseudoSST: done'
180    
181  end subroutine oobs_pseudoSST
182
183  !--------------------------------------------------------------------------
184  ! oobs_computeObsData
185  !--------------------------------------------------------------------------
186
187  subroutine oobs_computeObsData(obsData, iceDomainIndexes, iceLons, iceLats, iceThinning, &
188                                 outputSST, outputFreshWaterST, outputFileName, &
189                                 datePrint, timePrint, &
190                                 seaWaterFraction, seaWaterThreshold, inlandWaterPoints)
191    !
192    !:Purpose: pseudo SST data are put into obsSpaceData  
193    !          and written into an SQLite file
194    
195    implicit none
196    
197    ! Arguments:
198    type(struct_obs) , intent(inout) :: obsData            ! obsSpaceData   
199    integer          , intent(in)    :: iceDomainIndexes(:)! array of the ice-covered point indexes
200    real(4)          , intent(in)    :: iceLons(:)         ! longitudes of sea ice 
201    real(4)          , intent(in)    :: iceLats(:)         ! latitudes of sea ice 
202    integer          , intent(in)    :: iceThinning        ! generate pseudo obs in every 'iceThinning' points   
203    real(4)          , intent(in)    :: outputSST          ! output SST value for pseudo observations
204    real(4)          , intent(in)    :: outputFreshWaterST ! output fresh water surface temperature for pseudo obs
205    character(len=*) , intent(in)    :: outputFileName    
206    integer          , intent(in)    :: datePrint
207    integer          , intent(in)    :: timePrint
208    real(4)          , intent(in)    :: seaWaterFraction(:)! sea water fraction data: 0: fresh water; 1: sea water
209    real(4)          , intent(in)    :: seaWaterThreshold  ! to distinguish inland water from sea water 
210    integer          , intent(in)    :: inlandWaterPoints  ! number of inland water points 
211     
212    ! Locals:
213    real(pre_obsReal)           :: obsLon, obsLat
214    real(4)                     :: obsValue
215    integer                     :: iceIndex, iceDomainDimension, pseudoObsDimension
216    integer                     :: codeType, headerIndex
217    integer                     :: coordinatesIndex, counterThinning, checkInlandWatersCount, checkSeaWatersCount
218    character(len=*), parameter :: myName = 'oobs_computeObsData'
219    
220    iceDomainDimension = size(iceDomainIndexes)
221    pseudoObsDimension = floor(real((iceDomainDimension - inlandWaterPoints) / iceThinning)) + inlandWaterPoints
222      
223    write(*,*) myName//': sea-ice domain dimension: ', iceDomainDimension
224    write(*,*) myName//': pseudo obs vector dimension: ', pseudoObsDimension
225    write(*,*) myName//': pseudo SST obs will be generated in every ', iceThinning, &
226    ' points of the sea-ice field for sea water, '
227    write(*,*) myName//': and in every point for inland waters, where sea water fraction <= ', seaWaterThreshold
228    write(*,*) myName//': number of inland waters points: ', inlandWaterPoints  
229    
230    call obs_initialize(obsData, numHeader_max_opt = pseudoObsDimension, &
231                        numBody_max_opt = pseudoObsDimension, mpi_local_opt = .true.)
232    codeType = codtyp_get_codtyp('pseudosfc')
233    
234    headerIndex = 1
235    counterThinning = iceThinning
236    checkInlandWatersCount = 0
237    checkSeaWatersCount = 0
238    
239    do iceIndex = 1, iceDomainDimension 
240
241      if (headerIndex > pseudoObsDimension ) cycle
242      
243      coordinatesIndex = iceDomainIndexes(iceIndex)
244      obsLon   = iceLons(coordinatesIndex)
245      obsLat   = iceLats(coordinatesIndex)
246 
247      if (seaWaterFraction(coordinatesIndex) <= seaWaterThreshold) then
248        obsValue = (1.0d0 - seaWaterFraction(coordinatesIndex)) * outputFreshWaterST + &
249                   seaWaterFraction(coordinatesIndex)* outputSST
250        checkInlandWatersCount =  checkInlandWatersCount + 1
251      else
252        if (counterThinning == iceThinning) then  
253          obsValue = outputSST
254          checkSeaWatersCount = checkSeaWatersCount + 1	
255          counterThinning = 1
256        else
257          counterThinning = counterThinning + 1
258          cycle
259        end if
260      end if
261
262      call obs_setFamily(obsData, 'SF'   , headerIndex)
263      call obs_headSet_i(obsData, OBS_ONM, headerIndex, headerIndex)
264      call obs_headSet_i(obsData, OBS_ITY, headerIndex, codeType)
265      call obs_headSet_r(obsData, OBS_LAT, headerIndex, obsLat)
266      call obs_headSet_r(obsData, OBS_LON, headerIndex, obsLon)
267      call obs_bodySet_r(obsData, OBS_VAR, headerIndex, obsValue)
268      call obs_bodySet_i(obsData, OBS_VNM, headerIndex, bufr_sst)  
269      call     obs_set_c(obsData, 'STID' , headerIndex, 'ABOG')
270      call obs_headSet_i(obsData, OBS_NLV, headerIndex, 1)
271      call obs_headSet_i(obsData, OBS_RLN, headerIndex, headerIndex)
272      call obs_headSet_i(obsData, OBS_DAT, headerIndex, datePrint / 100)
273      call obs_headSet_i(obsData, OBS_ETM, headerIndex, timePrint)
274      headerIndex = headerIndex + 1
275    end do 
276    
277    call sqlr_writePseudoSSTobs(obsData, 'SF', outputFileName) 
278 
279    ! Deallocate obsSpaceData
280    call obs_finalize(obsData)
281
282  end subroutine oobs_computeObsData
283
284end module oceanObservations_mod