123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- ! File: m_superobs.F90
- !
- ! Created: 02 Sep 2008
- !
- ! Author: Pavel Sakov
- ! NERSC
- !
- ! Purpose: Superobing observations to model grid
- !
- ! Description: Conducts the following operations:
- ! - determine the number of observations with this tag
- ! - sort observations according to the pivot values
- ! - calculate superobs
- !
- ! Modifications: 14.10.2009 PS: added cycle over the data age, so that it only
- ! superobs the data of the same age. Do not set
- ! age if you assiilate data of different age in
- ! one go.
- ! 15.11.2009 PS: fixed a defect at l.102: it should be
- ! "thisob = obs_now(sorted(o))", not
- ! "thisob = obs_now(o)"
- ! 17.11.2009 PS: extended to handle the 3D case
- module m_superobs
- use mod_measurement
- use m_bilincoeff
- implicit none
- integer, parameter, private :: STRLEN = 512
- logical, parameter, private :: TEST = .false.
- contains
- subroutine superob(obstag, nobs, obs, ni, nj, modlon, modlat, nnewobs, newobs, is3d)
- character(*), intent(in) :: obstag
- integer, intent(in) :: nobs
- type(measurement), intent(inout), dimension(:) :: obs
- integer, intent(in) :: ni, nj
- real, dimension(:,:), intent(in) :: modlon, modlat
- integer, intent(inout) :: nnewobs
- type(measurement), intent(inout), dimension(:) :: newobs
- logical, intent(in), optional :: is3d
- integer :: age_min, age_max, nobs_total, nobs_now, age
- integer :: o, iprev, jprev, kprev, ii, ii_now
- logical, dimension(nobs) :: mask
- integer, dimension(nobs) :: sorted
- type(measurement), dimension(nobs) :: obs_now
- real(8), dimension(1) :: nobs_real
- type(measurement) :: thisob
- real :: n, nmax, valsum, valsqsum, varinvsum, lonsum, latsum, depthsum, valmax, valmin
- real :: a1sum, a2sum, a3sum, a4sum
- integer :: nlon_pos, nlon_neg
- real :: lonsum_abs
- integer, dimension(nobs) :: kpiv ! vertical index for 3D case
- integer, dimension(nobs) :: ids ! ids of obs contributing to this superob
- integer :: fid
- kpiv(1:nobs)=0
- ! find the range of the data age
- !
- age_min = minval(obs % date)
- age_max = maxval(obs % date)
- print *, 'min age =', age_min
- print *, 'max age =', age_max
- ! get the total number of observations to process
- !
- mask = .false.
- do o = 1, nobs
- if (trim(obs(o) % id) == trim(obstag)) then
- mask(o) = .true.
- end if
- obs(o) % orig_id = o
- end do
- nobs_total = count(mask)
- print *, 'total # of obs of all types =', nobs
- print *, 'total # of obs of type "', trim(obstag), '" =', nobs_total
- if (TEST) then
- open(101, file = 'superobs.txt', access = 'sequential', status = 'replace')
- end if
- ii = 0
- do age = age_min, age_max
- ! trim() prevents vectorising below
- mask = .false.
- do o = 1, nobs
- if (trim(obs(o) % id) == trim(obstag) .and. obs(o) % date == age .and. obs(o) % status) then
- mask(o) = .true.
- end if
- end do
- nobs_now = count(mask)
- print *, 'age =', age
- print *, ' nobs =', nobs_now
- if (nobs_now == 0) then
- cycle
- end if
- obs_now(1 : nobs_now) = pack(obs(1 : nobs), mask)
- nobs_real(1) = nobs_now
- if (.not. present(is3d) .or. .not. is3d) then
- call sortgriddedobs(nobs_real, obs_now % ipiv, obs_now % jpiv, sorted)
- else
- kpiv = z2k(obs_now % depth)
- call sortgriddedobs3d(nobs_real, obs_now % ipiv, obs_now % jpiv,&
- kpiv, sorted)
- end if
-
- iprev = 0
- jprev = 0
- kprev = 0
- nmax = 0
- ii_now = 0
- do o = 1, nobs_now + 1
- if (o <= nobs_now) then
- thisob = obs_now(sorted(o))
- else
- thisob % ipiv = -1 ! to force write of the previous measurement
- end if
- if (thisob % ipiv /= iprev .or. thisob % jpiv /= jprev .or. kpiv(sorted(o)) /= kprev) then
- if (ii_now > 0) then ! write the previous measurement
- newobs(ii) % d = valsum / n
- newobs(ii) % var = 1.0d0 / varinvsum
- newobs(ii) % id = obstag
- if (nlon_pos == 0 .or. nlon_neg == 0 .or. lonsum_abs / n < 90.0d0) then
- newobs(ii) % lon = lonsum / n
- else
- lonsum = lonsum + real(nlon_neg) * 360.0d0;
- newobs(ii) % lon = lonsum / n
- if (newobs(ii) % lon > 180.0d0) then
- newobs(ii) % lon = newobs(ii) % lon - 360.0d0
- end if
- end if
- newobs(ii) % lat = latsum / n
- newobs(ii) % depth = depthsum / n
- newobs(ii) % ipiv = iprev
- newobs(ii) % jpiv = jprev
- newobs(ii) % ns = 0 ! not 100% sure
- newobs(ii) % a1 = a1sum / n
- newobs(ii) % a2 = a2sum / n
- newobs(ii) % a3 = a3sum / n
- newobs(ii) % a4 = a4sum / n
- newobs(ii) % status = .true.
- newobs(ii) % i_orig_grid = -1
- newobs(ii) % j_orig_grid = -1
- newobs(ii) % h = n
- newobs(ii) % date = age
- newobs(ii) % orig_id = ids(1) ! ID of the first ob
- nmax = max(n, nmax)
- if (TEST) then
- write(101, '(a, g10.3)') 'total # of obs = ', n
- write(101, '(a, i6)') ' index = ', ii
- write(101, '(a, g10.3)') ' d = ', newobs(ii) % d
- write(101, '(a, g10.3)') ' var = ', newobs(ii) % var
- write(101, '(a, g10.3)') ' lon = ', newobs(ii) % lon
- write(101, '(a, g10.3)') ' lat = ', newobs(ii) % lat
- write(101, '(a, i4)') ' ipiv = ', newobs(ii) % ipiv
- write(101, '(a, i4)') ' jpiv = ', newobs(ii) % jpiv
- write(101, '(a, g10.3)') ' depth = ', newobs(ii) % depth
- write(101, '(a, g10.3)') ' a1 = ', newobs(ii) % a1
- write(101, '(a, g10.3)') ' a2 = ', newobs(ii) % a2
- write(101, '(a, g10.3)') ' a3 = ', newobs(ii) % a3
- write(101, '(a, g10.3)') ' a4 = ', newobs(ii) % a4
- write(101, '(a)') '---'
- call superobs_dump(trim(obstag), ii, ids, int(n))
- end if
- end if
- if (o > nobs_now) then
- exit
- end if
- ii = ii + 1
- ii_now = ii_now + 1
- if (TEST) then
- write(101, '(a, i6)') 'new superob, index = ', ii
- end if
- n = 0.0
- valsum = 0.0d0
- valsqsum = 0.0d0
- varinvsum = 0.0d0
- lonsum = 0.0d0
- latsum = 0.0d0
- depthsum = 0.0
- a1sum = 0.0d0
- a2sum = 0.0d0
- a3sum = 0.0d0
- a4sum = 0.0d0
- valmax = -1.0d+20
- valmin = 1.0d+20
- iprev = thisob % ipiv
- jprev = thisob % jpiv
- kprev = kpiv(sorted(o))
- nlon_pos = 0
- nlon_neg = 0
- lonsum_abs = 0.0d0
- end if
- n = n + 1.0
- valsum = valsum + thisob % d
- valsqsum = valsqsum + (thisob % d) ** 2
- varinvsum = varinvsum + 1.0 / thisob % var
- lonsum = lonsum + thisob % lon
- lonsum_abs = lonsum_abs + abs(thisob % lon)
- if (thisob % lon >= 0.0) then
- nlon_pos = nlon_pos + 1
- else
- nlon_neg = nlon_neg + 1
- end if
- latsum = latsum + thisob % lat
- depthsum = depthsum + thisob % depth
- a1sum = a1sum + thisob % a1
- a2sum = a2sum + thisob % a2
- a3sum = a3sum + thisob % a3
- a4sum = a4sum + thisob % a4
- valmin = min(valmin, thisob % d)
- valmax = max(valmax, thisob % d)
- ids(int(n)) = thisob % orig_id;
- if (TEST) then
- write(101, '(a, i6)') ' obs index = ', sorted(o)
- write(101, '(a, g10.3)') ' d = ', thisob % d
- write(101, '(a, g10.3)') ' var = ', thisob % var
- write(101, '(a, g10.3)') ' lon = ', thisob % lon
- write(101, '(a, g10.3)') ' lat = ', thisob % lat
- write(101, '(a, i4)') ' ipiv = ', thisob % ipiv
- write(101, '(a, i4)') ' jpiv = ', thisob % jpiv
- write(101, '(a, g10.3)') ' depth = ', thisob % depth
- write(101, '(a, g10.3)') ' a1 = ', thisob % a1
- write(101, '(a, g10.3)') ' a2 = ', thisob % a2
- write(101, '(a, g10.3)') ' a3 = ', thisob % a3
- write(101, '(a, g10.3)') ' a4 = ', thisob % a4
- end if
- end do ! obs for this age
- print *, ' nsuperobs =', ii_now
- end do ! age
- if (TEST) then
- close(101)
- end if
- nnewobs = ii
- print *, 'Superobing("', trim(obstag), '"):'
- print *, ' ', nobs, 'observations ->', nnewobs, 'observations'
- print *, ' max # of obs found in a grid cell =', int(nmax)
- end subroutine superob
- function z2k(z)
- real, intent(in), dimension(:) :: z
- integer, dimension(size(z)) :: z2k
- integer :: i, nz
- nz = size(z)
- do i = 1, nz
- if (z(i) < 3.0d0) then
- z2k(i) = 1
- elseif (z(i) < 6.0d0) then
- z2k(i) = 2
- elseif (z(i) < 10.0d0) then
- z2k(i) = 3
- elseif (z(i) < 100.0d0) then
- z2k(i) = int(z(i) / 10.0d0) + 3
- elseif (z(i) < 1000.0d0) then
- z2k(i) = int(z(i) / 25.0d0) + 9
- else
- z2k(i) = int(z(i) / 50.0d0) + 29
- end if
- end do
- end function z2k
- subroutine superobs_dump(tag, id, ids, n)
- use nfw_mod
- character(*) :: tag
- integer, intent(in) :: id
- integer, intent(in) :: ids(n)
- integer, intent(in) :: n
- character(STRLEN) :: fname
- character(64) :: dname
- character(64) :: vname
- integer :: ncid, did(1), vid
- if (id > NF_MAX_DIMS) then
- return
- end if
- write(fname, '(a, a, a)') 'superobs-', trim(tag), '.nc'
- if (id == 1) then
- print *, 'dumping obs ids for each superob to "', trim(fname), '"'
- call nfw_create(fname, nf_clobber, ncid)
- else
- call nfw_open(fname, nf_write, ncid)
- call nfw_redef(fname, ncid)
- end if
- write(dname, '(a,i0)') 'd', id
- call nfw_def_dim(fname, ncid, trim(dname), n, did(1))
- write(vname, '(a,i0)') 'v', id
- call nfw_def_var(fname, ncid, trim(vname), nf_int, 1, did(1), vid)
- call nfw_enddef(fname, ncid)
- call nfw_put_var_int(fname, ncid, vid, ids)
- call nfw_close(fname, ncid)
- end subroutine superobs_dump
- end module m_superobs
|