FV3 Bundle
qg_obs_data.F90
Go to the documentation of this file.
1 ! (C) Copyright 2009-2016 ECMWF.
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 ! In applying this licence, ECMWF does not waive the privileges and immunities
6 ! granted to it by virtue of its status as an intergovernmental organisation nor
7 ! does it submit to any jurisdiction.
8 
9 !> Handle observations for the QG model
10 
12 
13 use iso_c_binding
14 use string_f_c_mod
15 use config_mod
16 use datetime_mod
17 use duration_mod
18 use qg_goms_mod
19 use qg_locs_mod
22 use qg_vars_mod
23 use fckit_log_module, only : fckit_log
24 use kinds
25 
26 implicit none
27 private
28 
30 public :: obs_data_registry
31 
32 ! ------------------------------------------------------------------------------
33 integer, parameter :: max_string=800
34 ! ------------------------------------------------------------------------------
35 
36 !> A type to represent observation data
38  integer :: ngrp
39  character(len=max_string) :: filein, fileout
40  type(group_data), pointer :: grphead => null()
41 end type obs_data
42 
43 #define LISTED_TYPE obs_data
44 
45 !> Linked list interface - defines registry_t type
46 #include "oops/util/linkedList_i.f"
47 
48 !> Global registry
49 type(registry_t) :: obs_data_registry
50 
51 ! ------------------------------------------------------------------------------
52 
53 !> A type to represent a linked list of observation group data
55  character(len=50) :: grpname
56  type(group_data), pointer :: next => null()
57  integer :: nobs
58  integer, allocatable :: seqnos(:)
59  type(datetime), allocatable :: times(:)
60  type(column_data), pointer :: colhead => null()
61 end type group_data
62 
63 ! ------------------------------------------------------------------------------
64 
65 !> A type to represent a linked list of observation columns
67  character(len=50) :: colname
68  type(column_data), pointer :: next => null()
69  integer :: ncol
70  real(kind=kind_real), allocatable :: values(:,:)
71 end type column_data
72 
73 ! ------------------------------------------------------------------------------
74 
75 !> Fortran generic
76 interface obs_count
78 end interface obs_count
79 
80 ! ------------------------------------------------------------------------------
81 contains
82 ! ------------------------------------------------------------------------------
83 !> Linked list implementation
84 #include "oops/util/linkedList_c.f"
85 
86 ! ------------------------------------------------------------------------------
87 
88 subroutine obs_setup(fin, fout, self)
89 implicit none
90 type(obs_data), intent(inout) :: self
91 character(len=*), intent(in) :: fin, fout
92 
93 self%ngrp=0
94 self%filein =fin
95 self%fileout=fout
96 
97 if (self%filein/="") call obs_read(self)
98 call fckit_log%debug("TRACE: qg_obs_data:obs_setup: done")
99 
100 end subroutine obs_setup
101 
102 ! ------------------------------------------------------------------------------
103 
104 subroutine obs_delete(self)
105 implicit none
106 type(obs_data), intent(inout) :: self
107 type(group_data), pointer :: jgrp
108 type(column_data), pointer :: jcol
109 integer :: jo
110 
111 if (self%fileout/="") call obs_write(self)
112 
113 do while (associated(self%grphead))
114  jgrp=>self%grphead
115  self%grphead=>jgrp%next
116  do jo=1,jgrp%nobs
117  call datetime_delete(jgrp%times(jo))
118  enddo
119  deallocate(jgrp%times)
120  do while (associated(jgrp%colhead))
121  jcol=>jgrp%colhead
122  jgrp%colhead=>jcol%next
123  deallocate(jcol%values)
124  deallocate(jcol)
125  enddo
126  deallocate(jgrp)
127 enddo
128 
129 end subroutine obs_delete
130 
131 ! ------------------------------------------------------------------------------
132 
133 subroutine obs_get(self, req, col, ovec)
134 implicit none
135 type(obs_data), intent(in) :: self
136 character(len=*), intent(in) :: req, col
137 type(obs_vect), intent(inout) :: ovec
138 
139 type(group_data), pointer :: jgrp
140 type(column_data), pointer :: jcol
141 integer :: jo, jc
142 character(len=250) :: record
143 
144 write(record,*)"obs_get req=",req
145 call fckit_log%info(record)
146 write(record,*)"obs_get col=",col
147 call fckit_log%info(record)
148 
149 ! Find obs group
150 call findgroup(self,req,jgrp)
151 if (.not.associated(jgrp)) then
152  jgrp=>self%grphead
153  do while (associated(jgrp))
154  write(record,*)"Group ",jgrp%grpname," exists."
155  call fckit_log%info(record)
156  jgrp=>jgrp%next
157  enddo
158  write(record,*)"Cannot find ",req," ."
159  call fckit_log%error(record)
160  call abor1_ftn("qg_obs_get: obs group not found")
161 endif
162 
163 ! Find obs column
164 call findcolumn(jgrp,col,jcol)
165 if (.not.associated(jcol)) call abor1_ftn("qg_obs_get: obs column not found")
166 
167 ! Get data
168 if (allocated(ovec%values)) deallocate(ovec%values)
169 ovec%nobs=jgrp%nobs
170 ovec%ncol=jcol%ncol
171 allocate(ovec%values(ovec%ncol,ovec%nobs))
172 
173 do jo=1,jgrp%nobs
174  do jc=1,jcol%ncol
175  ovec%values(jc,jo)=jcol%values(jc,jo)
176  enddo
177 enddo
178 
179 write(record,*)"obs_get nobs, ncol=",jgrp%nobs,jcol%ncol
180 call fckit_log%debug("TRACE: " // record)
181 
182 end subroutine obs_get
183 
184 ! ------------------------------------------------------------------------------
185 
186 subroutine obs_put(self, req, col, ovec)
187 implicit none
188 type(obs_data), intent(inout) :: self
189 character(len=*), intent(in) :: req, col
190 type(obs_vect), intent(in) :: ovec
191 
192 type(group_data), pointer :: jgrp
193 type(column_data), pointer :: jcol
194 integer :: jo, jc
195 character(len=250) :: record
196 
197 ! Find obs group
198 call findgroup(self,req,jgrp)
199 if (.not.associated(jgrp)) then
200  jgrp=>self%grphead
201  do while (associated(jgrp))
202  write(record,*)"Group ",jgrp%grpname," exists."
203  call fckit_log%info(record)
204  jgrp=>jgrp%next
205  enddo
206  write(record,*)"Cannot find ",req," ."
207  call fckit_log%error(record)
208  call abor1_ftn("qg_obs_put: obs group not found")
209 endif
210 
211 ! Find obs column (and add it if not there)
212 call findcolumn(jgrp,col,jcol)
213 if (.not.associated(jcol)) then
214  if (.not.associated(jgrp%colhead)) call abor1_ftn("qg_obs_put: no locations")
215  jcol=>jgrp%colhead
216  do while (associated(jcol%next))
217  jcol=>jcol%next
218  enddo
219  allocate(jcol%next)
220  jcol=>jcol%next
221 
222  jcol%colname=col
223  jcol%ncol=ovec%ncol
224  allocate(jcol%values(jcol%ncol,jgrp%nobs))
225 endif
226 
227 ! Put data
228 if (ovec%nobs/=jgrp%nobs) call abor1_ftn("qg_obs_put: error obs number")
229 if (ovec%ncol/=jcol%ncol) call abor1_ftn("qg_obs_put: error col number")
230 do jo=1,jgrp%nobs
231  do jc=1,jcol%ncol
232  jcol%values(jc,jo)=ovec%values(jc,jo)
233  enddo
234 enddo
235 
236 end subroutine obs_put
237 
238 ! ------------------------------------------------------------------------------
239 
240 subroutine obs_locations(c_key_self, lreq, c_req, c_t1, c_t2, c_key_locs) bind(c,name='qg_obsdb_locations_f90')
241 implicit none
242 integer(c_int), intent(in) :: c_key_self
243 integer(c_int), intent(in) :: lreq
244 character(kind=c_char,len=1), intent(in) :: c_req(lreq+1)
245 type(c_ptr), intent(in) :: c_t1, c_t2
246 integer(c_int), intent(in) :: c_key_locs
247 
248 type(obs_data), pointer :: self
249 character(len=lreq) :: req
250 type(datetime) :: t1, t2
251 type(qg_locs), pointer :: locs
252 type(obs_vect) :: ovec
253 character(len=8) :: col="Location"
254 integer :: nobs
255 integer, allocatable :: mobs(:)
256 
257 call obs_data_registry%get(c_key_self, self)
258 call c_f_string(c_req, req)
259 call c_f_datetime(c_t1, t1)
260 call c_f_datetime(c_t2, t2)
261 
262 call obs_count(self, req, t1, t2, nobs)
263 allocate(mobs(nobs))
264 call obs_count(self, req, t1, t2, mobs)
265 call obs_time_get(self, req, col, t1, t2, ovec)
266 
267 call qg_locs_registry%init()
268 call qg_locs_registry%add(c_key_locs)
269 call qg_locs_registry%get(c_key_locs,locs)
270 
271 call qg_loc_setup(locs, ovec, mobs)
272 
273 deallocate(ovec%values)
274 deallocate(mobs)
275 
276 end subroutine obs_locations
277 
278 ! ------------------------------------------------------------------------------
279 
280 subroutine obs_generate(c_key_self, lreq, c_req, c_conf, c_bgn, c_step, ktimes, kobs) bind(c,name='qg_obsdb_generate_f90')
281 implicit none
282 integer(c_int), intent(in) :: c_key_self
283 integer(c_int), intent(in) :: lreq
284 character(kind=c_char,len=1), intent(in) :: c_req(lreq+1)
285 type(c_ptr), intent(in) :: c_conf
286 type(c_ptr), intent(in) :: c_bgn
287 type(c_ptr), intent(in) :: c_step
288 integer(c_int), intent(in) :: ktimes
289 integer(c_int), intent(inout) :: kobs
290 type(obs_data), pointer :: self
291 character(len=lreq) :: req
292 type(datetime) :: bgn
293 type(duration) :: step
294 real(c_double) :: err
295 integer :: nobs, ncol
296 
297 integer :: nlocs
298 type(datetime), allocatable :: times(:)
299 type(obs_vect) :: obsloc, obserr
300 
301 call obs_data_registry%get(c_key_self, self)
302 call c_f_string(c_req, req)
303 call c_f_datetime(c_bgn, bgn)
304 call c_f_duration(c_step, step)
305 
306 nlocs = config_get_int(c_conf, "obs_density");
307 kobs=nlocs*ktimes;
308 
309 allocate(times(kobs))
310 
311 call generate_locations(c_conf, nlocs, ktimes, bgn, step, times, obsloc)
312 call obs_create(self, trim(req), times, obsloc)
313 
314 deallocate(times)
315 deallocate(obsloc%values)
316 
317 ! Create obs error
318 err = config_get_real(c_conf, "obs_error");
319 ncol = config_get_int(c_conf, "nval");
320 call obsvec_setup(obserr,ncol,kobs)
321 obserr%values(:,:)=err
322 call obs_put(self, trim(req), "ObsErr", obserr)
323 deallocate(obserr%values)
324 
325 end subroutine obs_generate
326 
327 ! ------------------------------------------------------------------------------
328 
329 subroutine obs_nobs(c_key_self, lreq, c_req, kobs) bind(c,name='qg_obsdb_nobs_f90')
330 implicit none
331 integer(c_int), intent(in) :: c_key_self
332 integer(c_int), intent(in) :: lreq
333 character(kind=c_char,len=1), intent(in) :: c_req(lreq+1)
334 integer(c_int), intent(inout) :: kobs
335 
336 type(obs_data), pointer :: self
337 character(len=lreq) :: req
338 integer :: iobs
339 
340 call obs_data_registry%get(c_key_self, self)
341 call c_f_string(c_req, req)
342 
343 call obs_count(self, req, iobs)
344 kobs = iobs
345 
346 end subroutine obs_nobs
347 
348 ! ------------------------------------------------------------------------------
349 
350 subroutine obs_time_get(self, req, col, t1, t2, ovec)
351 implicit none
352 type(obs_data), intent(in) :: self
353 character(len=*), intent(in) :: req, col
354 type(datetime), intent(in) :: t1, t2
355 type(obs_vect), intent(inout) :: ovec
356 
357 type(group_data), pointer :: jgrp
358 type(column_data), pointer :: jcol
359 integer :: jo, jc, iobs
360 
361 ! Find obs group
362 call findgroup(self,req,jgrp)
363 if (.not.associated(jgrp)) call abor1_ftn("obs_time_get: obs group not found")
364 
365 ! Find obs column
366 call findcolumn(jgrp,col,jcol)
367 if (.not.associated(jcol)) call abor1_ftn("obs_time_get: obs column not found")
368 
369 ! Time selection
370 iobs=0
371 do jo=1,jgrp%nobs
372  if (t1<jgrp%times(jo) .and. jgrp%times(jo)<=t2) iobs=iobs+1
373 enddo
374 
375 ! Get data
376 if (ovec%nobs/=iobs .or. ovec%ncol/=jcol%ncol) then
377  if (allocated(ovec%values)) deallocate(ovec%values)
378  ovec%nobs=iobs
379  ovec%ncol=jcol%ncol
380  allocate(ovec%values(ovec%ncol,ovec%nobs))
381 endif
382 
383 iobs=0
384 do jo=1,jgrp%nobs
385  if (t1<jgrp%times(jo) .and. jgrp%times(jo)<=t2) then
386  iobs=iobs+1
387  do jc=1,jcol%ncol
388  ovec%values(jc,iobs)=jcol%values(jc,jo)
389  enddo
390  endif
391 enddo
392 
393 end subroutine obs_time_get
394 
395 ! ------------------------------------------------------------------------------
396 
397 subroutine obs_count_time(self, req, t1, t2, kobs)
398 implicit none
399 type(obs_data), intent(in) :: self
400 character(len=*), intent(in) :: req
401 type(datetime), intent(in) :: t1, t2
402 integer, intent(inout) :: kobs
403 
404 type(group_data), pointer :: jgrp
405 integer :: jo
406 
407 ! Find obs group
408 call findgroup(self,req,jgrp)
409 if (.not.associated(jgrp)) call abor1_ftn("obs_count: obs group not found")
410 
411 ! Time selection
412 kobs=0
413 do jo=1,jgrp%nobs
414  if (t1<jgrp%times(jo) .and. jgrp%times(jo)<=t2) kobs=kobs+1
415 enddo
416 
417 end subroutine obs_count_time
418 
419 ! ------------------------------------------------------------------------------
420 
421 subroutine obs_count_indx(self, req, t1, t2, kobs)
422 implicit none
423 type(obs_data), intent(in) :: self
424 character(len=*), intent(in) :: req
425 type(datetime), intent(in) :: t1, t2
426 integer, intent(inout) :: kobs(:)
427 
428 type(group_data), pointer :: jgrp
429 integer :: jo, io
430 
431 ! Find obs group
432 call findgroup(self,req,jgrp)
433 if (.not.associated(jgrp)) call abor1_ftn("obs_count: obs group not found")
434 
435 ! Time selection
436 io=0
437 do jo=1,jgrp%nobs
438  if (t1<jgrp%times(jo) .and. jgrp%times(jo)<=t2) then
439  io=io+1
440  kobs(io)=jo
441  endif
442 enddo
443 
444 end subroutine obs_count_indx
445 
446 ! ------------------------------------------------------------------------------
447 
448 subroutine obs_count_all(self, req, kobs)
449 implicit none
450 type(obs_data), intent(in) :: self
451 character(len=*), intent(in) :: req
452 integer, intent(inout) :: kobs
453 type(group_data), pointer :: jgrp
454 
455 call findgroup(self,req,jgrp)
456 
457 if (associated(jgrp)) then
458  kobs=jgrp%nobs
459 else
460  kobs=0
461 endif
462 
463 end subroutine obs_count_all
464 
465 ! ------------------------------------------------------------------------------
466 
467 subroutine obs_create(self, req, times, locs)
468 implicit none
469 type(obs_data), intent(inout) :: self
470 character(len=*), intent(in) :: req
471 type(datetime), intent(in) :: times(:)
472 type(obs_vect), intent(in) :: locs
473 type(group_data), pointer :: igrp
474 integer :: jo, jc
475 
476 call findgroup(self,req,igrp)
477 if (associated(igrp)) call abor1_ftn("obs_create: obs group already exists")
478 
479 if (associated(self%grphead)) then
480  igrp=>self%grphead
481  do while (associated(igrp%next))
482  igrp=>igrp%next
483  enddo
484  allocate(igrp%next)
485  igrp=>igrp%next
486 else
487  allocate(self%grphead)
488  igrp=>self%grphead
489 endif
490 
491 igrp%grpname=req
492 igrp%nobs=size(times)
493 allocate(igrp%times(igrp%nobs))
494 igrp%times(:)=times(:)
495 
496 allocate(igrp%colhead)
497 igrp%colhead%colname="Location"
498 igrp%colhead%ncol=3
499 allocate(igrp%colhead%values(3,igrp%nobs))
500 if (locs%ncol/=3) call abor1_ftn("obs_create: error locations not 3D")
501 if (locs%nobs/=igrp%nobs) call abor1_ftn("obs_create: error locations number")
502 do jo=1,igrp%nobs
503  do jc=1,3
504  igrp%colhead%values(jc,jo)=locs%values(jc,jo)
505  enddo
506 enddo
507 
508 self%ngrp=self%ngrp+1
509 
510 end subroutine obs_create
511 
512 ! ------------------------------------------------------------------------------
513 ! Private
514 ! ------------------------------------------------------------------------------
515 
516 subroutine obs_read(self)
517 implicit none
518 type(obs_data), intent(inout) :: self
519 integer :: iin, icol, jo, jc, jg, ncol
520 type(group_data), pointer :: jgrp
521 type(column_data), pointer :: jcol
522 real(kind=kind_real), allocatable :: ztmp(:)
523 character(len=20) :: stime
524 character(len=max_string+50) :: record
525 
526 iin=90
527 write(record,*)'obs_read: opening ',trim(self%filein)
528 call fckit_log%info(record)
529 open(unit=iin, file=trim(self%filein), form='formatted', action='read')
530 
531 read(iin,*)self%ngrp
532 do jg=1,self%ngrp
533  if (jg==1) then
534  allocate(self%grphead)
535  jgrp=>self%grphead
536  else
537  allocate(jgrp%next)
538  jgrp=>jgrp%next
539  endif
540  read(iin,*)jgrp%grpname
541  read(iin,*)jgrp%nobs
542  write(record,*)'obs_read: reading ',jgrp%nobs,' ',jgrp%grpname,' observations.'
543  call fckit_log%info(record)
544  allocate(jgrp%times(jgrp%nobs))
545 
546  read(iin,*)ncol
547  icol=0
548  do jc=1,ncol
549  if (jc==1) then
550  allocate(jgrp%colhead)
551  jcol=>jgrp%colhead
552  else
553  allocate(jcol%next)
554  jcol=>jcol%next
555  endif
556  read(iin,*)jcol%colname, jcol%ncol
557  icol=icol+jcol%ncol
558  allocate(jcol%values(jcol%ncol,jgrp%nobs))
559  enddo
560 
561  allocate(ztmp(icol))
562  do jo=1,jgrp%nobs
563  read(iin,*)stime,ztmp(:)
564  call datetime_create(stime,jgrp%times(jo))
565  icol=0
566  jcol=>jgrp%colhead
567  do while (associated(jcol))
568  do jc=1,jcol%ncol
569  icol=icol+1
570  jcol%values(jc,jo)=ztmp(icol)
571  enddo
572  jcol=>jcol%next
573  enddo
574  enddo
575  deallocate(ztmp)
576 enddo
577 
578 close(iin)
579 
580 end subroutine obs_read
581 
582 ! ------------------------------------------------------------------------------
583 
584 subroutine obs_write(self)
585 implicit none
586 type(obs_data), intent(in) :: self
587 integer :: iout, icol, jc, jo
588 type(group_data), pointer :: jgrp
589 type(column_data), pointer :: jcol
590 real(kind=kind_real), allocatable :: ztmp(:)
591 character(len=20) :: stime
592 
593 iout=91
594 open(unit=iout, file=trim(self%fileout), form='formatted', action='write')
595 
596 write(iout,*)self%ngrp
597 jgrp=>self%grphead
598 do while (associated(jgrp))
599  write(iout,*)jgrp%grpname
600  write(iout,*)jgrp%nobs
601 
602  icol=0
603  jcol=>jgrp%colhead
604  do while (associated(jcol))
605  icol=icol+1
606  jcol=>jcol%next
607  enddo
608  write(iout,*)icol
609 
610  icol=0
611  jcol=>jgrp%colhead
612  do while (associated(jcol))
613  write(iout,*)jcol%colname, jcol%ncol
614  icol=icol+jcol%ncol
615  jcol=>jcol%next
616  enddo
617 
618  allocate(ztmp(icol))
619  do jo=1,jgrp%nobs
620  icol=0
621  jcol=>jgrp%colhead
622  do while (associated(jcol))
623  do jc=1,jcol%ncol
624  icol=icol+1
625  ztmp(icol)=jcol%values(jc,jo)
626  enddo
627  jcol=>jcol%next
628  enddo
629  call datetime_to_string(jgrp%times(jo),stime)
630  write(iout,*)stime,ztmp(:)
631  enddo
632  deallocate(ztmp)
633 
634  jgrp=>jgrp%next
635 enddo
636 
637 close(iout)
638 
639 end subroutine obs_write
640 
641 ! ------------------------------------------------------------------------------
642 
643 subroutine findgroup(self,req,find)
644 type(obs_data), intent(in) :: self
645 character(len=*), intent(in) :: req
646 type(group_data), pointer, intent(inout) :: find
647 
648 find=>self%grphead
649 do while (associated(find))
650  if (find%grpname==req) exit
651  find=>find%next
652 enddo
653 
654 end subroutine findgroup
655 
656 ! ------------------------------------------------------------------------------
657 
658 subroutine findcolumn(grp,col,find)
659 type(group_data), intent(in) :: grp
660 character(len=*), intent(in) :: col
661 type(column_data), pointer, intent(inout) :: find
662 
663 find=>grp%colhead
664 do while (associated(find))
665  if (find%colname==col) exit
666  find=>find%next
667 enddo
668 
669 end subroutine findcolumn
670 
671 ! ------------------------------------------------------------------------------
672 
673 end module qg_obs_data
subroutine, public obs_put(self, req, col, ovec)
subroutine, public obs_setup(fin, fout, self)
Linked list implementation.
Definition: qg_obs_data.F90:89
subroutine obs_time_get(self, req, col, t1, t2, ovec)
subroutine obs_read(self)
subroutine obs_create(self, req, times, locs)
integer, parameter max_string
type(registry_t), public qg_locs_registry
Linked list interface - defines registry_t type.
Definition: qg_locs_mod.F90:37
subroutine findgroup(self, req, find)
type(registry_t), public obs_data_registry
Linked list interface - defines registry_t type.
Definition: qg_obs_data.F90:49
subroutine obs_generate(c_key_self, lreq, c_req, c_conf, c_bgn, c_step, ktimes, kobs)
subroutine generate_locations(c_conf, nlocs, ntimes, bgn, step, times, obsloc)
subroutine obs_nobs(c_key_self, lreq, c_req, kobs)
subroutine, public obs_get(self, req, col, ovec)
subroutine obs_write(self)
subroutine obs_count_indx(self, req, t1, t2, kobs)
Fortran module handling observation locations.
Definition: qg_locs_mod.F90:11
A type to represent a linked list of observation columns.
Definition: qg_obs_data.F90:66
Handle observations for the QG model.
Definition: qg_obs_data.F90:11
Fortran generic.
Definition: qg_obs_data.F90:76
real(kind=kind_real), parameter req
Earth radius at equator (m)
subroutine, public obs_delete(self)
Fortran module to handle variables for the QG model.
Definition: qg_vars_mod.F90:11
subroutine, public obsvec_setup(self, nc, no)
subroutine findcolumn(grp, col, find)
Fortran module handling interpolated (to obs locations) model variables.
Definition: qg_goms_mod.F90:11
subroutine obs_locations(c_key_self, lreq, c_req, c_t1, c_t2, c_key_locs)
subroutine, public qg_loc_setup(self, lvec, kobs)
subroutine obs_count_all(self, req, kobs)
A type to represent a linked list of observation group data.
Definition: qg_obs_data.F90:54
Fortran module for streamfunction observations for the QG model.
A type to represent observation data.
Definition: qg_obs_data.F90:37
Fortran module handling observation vectors.
subroutine obs_count_time(self, req, t1, t2, kobs)
Fortran derived type to represent an observation vector.