123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- ! File : p_prep_obs.F90
- !
- ! Created: unknown
- !
- ! Author: unknown
- !
- ! Purpose: Read data from different data sources and convert it to
- ! type(measurement).
- !
- ! Description: The code calls different subroutines for particular types of
- ! input data, depending on the source, observation type and
- ! format. The output is the array of type(measurement) that
- ! contains, in particular, pivot points and bilinear
- ! interpolation coefficients for each observation. This array
- ! is written to "observations.uf" in binary format.
- !
- ! Modifications: 30/01/2008 - Pavel Sakov gave a trim (formatted) -- sorry
- ! for that, could not stand -- and modified to allow in-situ
- ! argo data from ifremer.
- ! 02/09/2008 - Pavel Sakov added superobing for SST and SLA data
- ! 17/08/2010 PS - turned (3D) superobing on for Argo obs
- ! 09/11/2012 Geir Arne Waagbo: Added support for OSISAF ice drift obs
- program p_prep_obs
- use mod_measurement
- use mod_grid
- use m_read_CLS_header
- use m_read_CLS_data
- use m_read_CLS_SST_grid
- use m_read_MET_SST_grid
- use m_read_CLS_TSLA_grid
- use m_read_CLS_SST
- use m_read_CLS_SSH
- use m_read_CLS_SLA
- use m_read_CLS_TSLA
- use m_read_MET_SST
- use m_read_CERSAT_data
- use m_read_OSISAF_data
- use m_read_ifremer_argo
- use m_read_jpl_hice
- use m_read_FFI_glider
- use m_read_metno_icec
- use m_get_def_wet_point
- use m_write_wet_file
- use m_get_mod_grid
- use m_parse_blkdat
- use m_read_amsr_norsex
- use m_superobs
- use m_uobs
- implicit none
- integer, parameter :: STRLEN = 512
- type (measurement), allocatable :: data(:)
- type (measurement), allocatable :: obs(:)
- type (grid) :: gr
- integer :: nx, ny
- real, allocatable, dimension(:,:) :: depths, modlat, modlon
- integer, parameter :: maxobs = 5000000
- character(STRLEN) :: fname, fnamehdr, dataformat, producer
- character(len=3) :: form
- character(len=5) :: obstype
- character(len=1) :: offset
- integer :: nrobs
- integer :: grpoints, k
- real :: factor, var
- real :: rdummy, mindx, meandx
- logical :: data_eq_obs
- ! superobs
- logical :: dosuperob
- logical :: is3d
- integer :: nrsobs
- type(measurement), allocatable :: sobs(:)
- integer :: i
- integer :: nthisobs
- integer, allocatable, dimension(:) :: thisobs
- gr = default_grid
- data_eq_obs = .false.
- open(10, file = 'infile.data')
- read(10, '(a)') producer
- read(10, '(a)') obstype
- read(10, '(a)') fnamehdr
- read(10, '(a)') fname
- close(10)
- print *, 'Data producer: ', trim(producer)
- print *, 'Data to be processed for TOPAZ: ', trim(obstype)
- print *, 'Filenames to be processed are: "', trim(fnamehdr), '" "', trim(fname), '"'
- print *, 'Result of processing is stored in temporary file "observation.uf"'
- ! Get grid dimensions from blkdat.input
- !
- call parse_blkdat('idm ', 'integer', rdummy, nx)
- call parse_blkdat('jdm ', 'integer', rdummy, ny)
- allocate(depths(nx, ny))
- allocate(modlon(nx, ny))
- allocate(modlat(nx, ny))
- dosuperob = .false.
- is3d = .false.
- ! Fill the "data" array by calling subroutines specific for the producer
- ! and observation type
- !
- if (trim(producer) == 'Reynolds') then
- if (trim(obstype) == 'SST') then
- dosuperob = .true.
- call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_data(fname, obstype, dataformat, gr, form, data, factor, var)
- print*, 'Reynolds- ', obstype, ' data has been scaled by a factor = ', factor
- else
- stop 'ERROR: Reynolds only produce SST'
- endif
- else if (trim(Producer) == 'MET') then
- if (trim(obstype) == 'SST') then
- dosuperob = .true.
- call read_MET_SST_grid(fnamehdr, gr)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_MET_SST(fname, gr, data)
- else
- stop 'ERROR: OSTIA (MET) only produces SST'
- endif
- else if (trim(Producer) == 'NSIDC-AMSR') then
- if (trim(obstype) == 'ICEC') then
- dosuperob = .true.
- call read_amsr_norsex(fname, gr, data, obstype)
- allocate (obs(maxobs))
- else
- print *, 'No ',obstype, ' data from:', Producer
- stop 'ERROR: p_prep_obs'
- endif
- else if (trim(Producer) == 'METNO') then
- if (trim(obstype) == 'ICEC') then
- dosuperob = .true.
- call read_metno_icec_repro(fname, data, gr)
- allocate (obs(size(data)))
- elseif (index(obstype,'idrf')>0) then
- print *, 'OSISAF Ice Drift: ', obstype
- offset = obstype(5:5)
- print *, 'Offset: ', offset ! The number of days before analysis day
- dosuperob = .false.
- call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
- grpoints = gr % nx ! NB - 2 vector components - irregular grid
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_OSISAF_data(trim(fname), gr, data, grpoints, var, offset)
- print *, producer, obstype, 'data has been scaled by a factor = ', factor
- else
- print *, 'There can be no ', obstype,' data from', Producer
- stop
- endif
- elseif (trim(producer) == 'CLS') then
- if (trim(obstype) == 'SLA') then
- dosuperob = .true.
- ! call read_CLS_SST_grid() here because SST data grid has the same
- ! structure
- call read_CLS_SST_grid(fnamehdr, gr)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_SLA(fname, gr, data)
-
- elseif (trim(obstype) == 'SSH') then
- dosuperob = .true.
- call read_CLS_SST_grid(fnamehdr, gr)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_SSH(fname, gr, data)
- elseif (trim(obstype) == 'SST') then
- dosuperob = .true.
- call read_CLS_SST_grid(fnamehdr, gr)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_SST(fname, gr, data)
- elseif (trim(obstype) == 'TSLA') then
- dosuperob = .true.
- call read_CLS_TSLA_grid(fnamehdr, gr)
- print *, 'read_CLS_TSLA_grid finished, total # of obs = ', gr % nx
- grpoints = gr % nx
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_TSLA(fname,gr,data)
- else
- print *, 'data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
- stop 'ERROR: p_prep_obs'
- endif
- else if (trim(producer) == 'NSIDC') then
- if (trim(obstype) == 'ICEC') then
- dosuperob = .true.
- call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
- grpoints = gr % nx * gr % ny
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CLS_data(fname, obstype, dataformat, gr, form, data, factor, var)
- print *, producer, obstype, 'data has been scaled by a factor = ', factor
- else
- print *, 'no data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
- stop 'ERROR: p_prep_obs'
- endif
- else if (trim(producer) == 'CERSAT') then
- if (trim(obstype) == 'idrft') then
- dosuperob = .false.
- call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
- grpoints = gr % nx ! NB - 2 vector components - irregular grid
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_CERSAT_data(trim(fname), gr, data, grpoints, var)
- print *, producer, obstype, 'data has been scaled by a factor = ', factor
- else
- print *, 'no data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
- stop 'ERROR: p_prep_obs'
- endif
- elseif (trim(producer) == 'IFREMER') then
- dosuperob = .true.
- is3d = .true.
- read(fnamehdr, *) var
- print *, 'variance =', var
- call read_ifremer_argo(fname, obstype, var, nx, ny, data)
- ! PS: This is a flag to denote that read_ifremer_argo() takes care of
- ! filling type(measurement) array "data" in a correct way, and it should
- ! not be re-processed by calling get_def_wet_point(). This may not match
- ! the ideology behind the workflow adopted in this module and may be
- ! changed in future.
- !
- data_eq_obs = .true.
- elseif (trim(producer) == 'JPL') then
- dosuperob = .true.
- is3d = .false.
- read(fnamehdr, *) var
- print *, 'variance = ', var
- call read_jpl_hice(fname, obstype, var, nx, ny, data)
- ! see the comment for producer = IFREMER
- data_eq_obs = .true.
- elseif (trim(producer) == 'FFI') then
- dosuperob = .true.
- is3d = .true.
- read(fnamehdr, *) var
- print *, 'variance =', var
- call read_FFI_glider(fname, obstype, var, nx, ny, data)
- data_eq_obs = .true.
- elseif (trim(producer) == 'MYO') then
- if (trim(obstype) == 'TSLA') then
- dosuperob = .true.
- call read_MYO_TSLA_grid(fnamehdr, gr)
- print *, 'read_CLS_TSLA_grid finished, total # of obs = ', gr % nx
- grpoints = gr % nx
- allocate(data(grpoints))
- allocate(obs(maxobs))
- call read_MYO_TSLA(fnamehdr,fname,gr,data)
- print *, 'read_MYO_TSLA finished, SIZE(data) = ', SIZE(data)
- else
- print *, 'data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
- stop 'ERROR: p_prep_obs'
- endif
- else
- print *, 'unknown producer ', trim(producer), ' in "infile.data"'
- stop 'ERROR: p_prep_obs'
- endif
- ! Read position and depth from model grid
- !
- call get_mod_grid(modlon, modlat, depths, mindx, meandx, nx, ny)
- if (.not. data_eq_obs) then
- ! Compute bilinear coefficients
- ! Extract the defined and wet data points
- ! Write locations to ijfile to be used in TECPLOT
- !
- call get_def_wet_point(obs, data, gr, depths, modlat, modlon, nrobs, nx, ny)
- else
- call check_forland(data, depths, size(data), nx, ny)
- nrobs = size(data)
- allocate(obs(nrobs))
- obs = data
- end if
- deallocate(data)
- if (trim(obstype) == 'TSLA') then
- call set_re_TSLA(nrobs, obs, nx, ny, modlon, modlat)
- end if
- where (obs % d + 1.0 == obs % d)
- obs % status = .false.
- end where
- ! Superob dense 2D data
- !
- if (dosuperob) then
- allocate(sobs(nrobs))
- call superob(obstype, nrobs, obs, nx, ny, modlon, modlat, nrsobs, sobs, is3d)
-
- deallocate(obs)
- allocate(obs(nrsobs))
- obs = sobs(1 : nrsobs)
- nrobs = nrsobs
- deallocate(sobs)
- end if
- if (nrobs .ge. maxobs) then
- print *, 'max No. of data reached, increase it!'
- stop 'ERROR: p_prep_obs'
- elseif (nrobs .le. 1) then
- print *, 'less than one observation in the whole dataset'
- !PS 4/9/2011 stop 'ERROR: p_prep_obs: Not worth the money'
- end if
- ! Write data to the binary file "observations.uf"
- !
- call write_wet_file(obs, nrobs)
- call uobs_get(obs(1 : nrobs) % id, nrobs, .true.)
- allocate(thisobs(nrobs))
- do i = 1, nuobs
- nthisobs = 0
- do k = 1, nrobs
- if (trim(unique_obs(i)) == trim(obs(k) % id)) then
- nthisobs = nthisobs + 1
- thisobs(nthisobs) = k
- end if
- end do
- if (nthisobs > 0) then
- call obs2nc(nthisobs, obs(thisobs(1 : nthisobs)))
- end if
- end do
- deallocate(thisobs)
- print *, 'Last observation:'
- print '(a)',' obs var id lon lat depth ipiv jpiv nsup'//&
- ' 4-bilin-coeffs active orig (i,j) dp age orig_id'
- print '(2g10.2,a6,3f6.1,3i6,4f5.1,l5,2i7,f7.1,2i5)', obs(nrobs)
- deallocate(obs)
- deallocate(depths)
- deallocate(modlon)
- deallocate(modlat)
- print *, 'prep_obs: end of processing'
- end program p_prep_obs
- subroutine obs2nc(nobs, obs)
- use mod_measurement
- use nfw_mod
- implicit none
- integer, parameter :: STRLEN = 512
- integer, intent(in) :: nobs
- type(measurement), intent(in) :: obs(nobs)
- character(STRLEN) :: fname
- integer :: ncid, obsdimid(1), lon_id, lat_id, depth_id, d_id, var_id, age_id
- integer :: n_id, ipiv_id, jpiv_id
- integer :: n(nobs)
- ! Create netcdf file of observations
- !
- write(fname, '(a, a, a)') 'observations-', trim(obs(1) % id), '.nc'
- print *, 'dumping observations to "', trim(fname), '"'
- call nfw_create(fname, nf_clobber, ncid)
- call nfw_def_dim(fname, ncid, 'nobs', nobs, obsdimid(1))
- call nfw_def_var(fname, ncid, 'lon', nf_float, 1, obsdimid(1), lon_id)
- call nfw_def_var(fname, ncid, 'lat', nf_float, 1, obsdimid(1), lat_id)
- call nfw_def_var(fname, ncid, 'depth', nf_float, 1, obsdimid(1), depth_id)
- call nfw_def_var(fname, ncid, 'd', nf_float, 1, obsdimid(1), d_id)
- call nfw_def_var(fname, ncid, 'var', nf_float, 1, obsdimid(1), var_id)
- call nfw_def_var(fname, ncid, 'age', nf_int, 1, obsdimid(1), age_id)
- call nfw_def_var(fname, ncid, 'n', nf_int, 1, obsdimid(1), n_id)
- call nfw_def_var(fname, ncid, 'ipiv', nf_int, 1, obsdimid(1), ipiv_id)
- call nfw_def_var(fname, ncid, 'jpiv', nf_int, 1, obsdimid(1), jpiv_id)
- call nfw_enddef(fname, ncid)
- call nfw_put_var_double(fname, ncid, lon_id, obs(1:nobs) % lon)
- call nfw_put_var_double(fname, ncid, lat_id, obs(1:nobs) % lat)
- call nfw_put_var_double(fname, ncid, depth_id, obs(1:nobs) % depth)
- call nfw_put_var_double(fname, ncid, d_id, obs(1:nobs) % d)
- call nfw_put_var_double(fname, ncid, var_id, obs(1:nobs) % var)
- call nfw_put_var_int(fname, ncid, age_id, obs(1:nobs) % date)
- call nfw_put_var_int(fname, ncid, ipiv_id, obs(1:nobs) % ipiv)
- call nfw_put_var_int(fname, ncid, jpiv_id, obs(1:nobs) % jpiv)
- n = int(obs(1:nobs) % h)
- call nfw_put_var_int(fname, ncid, n_id, n)
-
- call nfw_close(fname, ncid)
- end subroutine obs2nc
- subroutine check_forland(data, depths, nrobs, ni, nj)
- use mod_measurement
- type (measurement), intent(inout), dimension(nrobs) :: data
- real, dimension(ni, nj), intent(in) :: depths
- integer, intent(in) :: nrobs
- integer, intent(in) :: ni, nj
- integer :: o, imin, jmin, imax, jmax, nmasked
- nmasked = 0
- do o = 1, nrobs
- imin = max(1, data(o) % ipiv - 1)
- jmin = max(1, data(o) % jpiv - 1)
- imax = min(ni, data(o) % ipiv + 2)
- jmax = min(nj, data(o) % jpiv + 2)
- if (any(depths(imin:imax,jmin:jmax) < 10.0 .or. depths(imin:imax,jmin:jmax) == depths(imin:imax,jmin:jmax) + 1.0)) then
- data(o) % status = .false.
- nmasked = nmasked + 1
- end if
- end do
- print *, " check_forland(): ", nmasked, "obs close to land masked"
- end subroutine check_forland
|