FV3 Bundle
qg_fields.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 fields for the QG model
10 
11 module qg_fields
12 
13 use config_mod
14 use qg_geom_mod
15 use qg_locs_mod
16 use qg_vars_mod
17 use qg_goms_mod
18 use calculate_pv, only : calc_pv
19 use netcdf
20 use kinds
21 
22 implicit none
23 private
24 
25 public :: qg_field, &
33 public :: qg_field_registry
34 
35 ! ------------------------------------------------------------------------------
36 
37 !> Fortran derived type to hold QG fields
38 type :: qg_field
39  type(qg_geom), pointer :: geom !< Geometry
40  integer :: nl !< Number of levels
41  integer :: nf !< Number of fields
42  logical :: lbc !< North-South boundary is present
43  real(kind=kind_real), pointer :: gfld3d(:,:,:) !< 3D fields
44  real(kind=kind_real), pointer :: x(:,:,:) !< Stream function
45  real(kind=kind_real), pointer :: q(:,:,:) !< Potential vorticity
46  real(kind=kind_real), pointer :: u(:,:,:) !< Zonal wind
47  real(kind=kind_real), pointer :: v(:,:,:) !< Meridional wind
48  real(kind=kind_real), pointer :: xbound(:) !< Streamfunction on walls
49  real(kind=kind_real), pointer :: x_north(:) !< Streamfunction on northern wall
50  real(kind=kind_real), pointer :: x_south(:) !< Streamfunction on southern wall
51  real(kind=kind_real), pointer :: qbound(:,:) !< PV on walls
52  real(kind=kind_real), pointer :: q_north(:,:) !< PV on northern wall
53  real(kind=kind_real), pointer :: q_south(:,:) !< PV on southern wall
54  character(len=1), allocatable :: fldnames(:) !< Variable identifiers
55 end type qg_field
56 
57 logical :: netcdfio = .true.
58 
59 #define LISTED_TYPE qg_field
60 
61 !> Linked list interface - defines registry_t type
62 #include "oops/util/linkedList_i.f"
63 
64 !> Global registry
65 type(registry_t) :: qg_field_registry
66 
67 ! ------------------------------------------------------------------------------
68 contains
69 ! ------------------------------------------------------------------------------
70 !> Linked list implementation
71 #include "oops/util/linkedList_c.f"
72 
73 ! ------------------------------------------------------------------------------
74 
75 subroutine create(self, geom, vars)
76 implicit none
77 type(qg_field), intent(inout) :: self
78 type(qg_geom), target, intent(in) :: geom
79 type(qg_vars), intent(in) :: vars
80 integer :: ioff
81 
82 self%geom => geom
83 self%nl = 2
84 self%nf = vars%nv
85 self%lbc = vars%lbc
86 
87 allocate(self%gfld3d(self%geom%nx,self%geom%ny,self%nl*self%nf))
88 self%gfld3d(:,:,:)=0.0_kind_real
89 
90 ioff=0
91 self%x => self%gfld3d(:,:,ioff+1:ioff+self%nl)
92 ioff =ioff + self%nl
93 
94 if (self%nf>1) then
95  self%q => self%gfld3d(:,:,ioff+1:ioff+self%nl)
96  ioff =ioff + self%nl
97  self%u => self%gfld3d(:,:,ioff+1:ioff+self%nl)
98  ioff =ioff + self%nl
99  self%v => self%gfld3d(:,:,ioff+1:ioff+self%nl)
100  ioff =ioff + self%nl
101 else
102  self%q => null()
103  self%u => null()
104  self%v => null()
105 endif
106 if (ioff/=self%nf*self%nl) call abor1_ftn ("qg_fields:create error number of fields")
107 
108 allocate(self%fldnames(self%nf))
109 self%fldnames(:)=vars%fldnames(:)
110 
111 if (self%lbc) then
112  allocate(self%xbound(4))
113  self%xbound(:)=0.0_kind_real
114  self%x_north => self%xbound(1:2)
115  self%x_south => self%xbound(3:4)
116  allocate(self%qbound(self%geom%nx,4))
117  self%qbound(:,:)=0.0_kind_real
118  self%q_north => self%qbound(:,1:2)
119  self%q_south => self%qbound(:,3:4)
120 else
121  self%xbound => null()
122  self%x_north => null()
123  self%x_south => null()
124  self%qbound => null()
125  self%q_north => null()
126  self%q_south => null()
127 endif
128 
129 call check(self)
130 
131 end subroutine create
132 
133 ! ------------------------------------------------------------------------------
134 
135 subroutine delete(self)
136 implicit none
137 type(qg_field), intent(inout) :: self
138 
139 call check(self)
140 
141 if (associated(self%gfld3d)) deallocate(self%gfld3d)
142 if (associated(self%xbound)) deallocate(self%xbound)
143 if (associated(self%qbound)) deallocate(self%qbound)
144 if (allocated(self%fldnames)) deallocate(self%fldnames)
145 
146 end subroutine delete
147 
148 ! ------------------------------------------------------------------------------
149 
150 subroutine zeros(self)
151 implicit none
152 type(qg_field), intent(inout) :: self
153 
154 call check(self)
155 
156 self%gfld3d(:,:,:) = 0.0_kind_real
157 if (self%lbc) then
158  self%xbound(:) = 0.0_kind_real
159  self%qbound(:,:) = 0.0_kind_real
160 endif
161 
162 end subroutine zeros
163 
164 ! ------------------------------------------------------------------------------
165 
166 subroutine dirac(self, c_conf)
167 use iso_c_binding
168 implicit none
169 type(qg_field), intent(inout) :: self
170 type(c_ptr), intent(in) :: c_conf !< Configuration
171 integer :: ndir,idir,ildir,ifdir,ioff
172 integer,allocatable :: ixdir(:),iydir(:)
173 character(len=3) :: idirchar
174 
175 call check(self)
176 
177 ! Get Diracs positions
178 ndir = config_get_int(c_conf,"ndir")
179 allocate(ixdir(ndir))
180 allocate(iydir(ndir))
181 do idir=1,ndir
182  write(idirchar,'(i3)') idir
183  ixdir(idir) = config_get_int(c_conf,"ixdir("//trim(adjustl(idirchar))//")")
184  iydir(idir) = config_get_int(c_conf,"iydir("//trim(adjustl(idirchar))//")")
185 end do
186 ildir = config_get_int(c_conf,"ildir")
187 ifdir = config_get_int(c_conf,"ifdir")
188 
189 ! Check
190 if (ndir<1) call abor1_ftn("qg_fields:dirac non-positive ndir")
191 if (any(ixdir<1).or.any(ixdir>self%geom%nx)) call abor1_ftn("qg_fields:dirac invalid ixdir")
192 if (any(iydir<1).or.any(iydir>self%geom%ny)) call abor1_ftn("qg_fields:dirac invalid iydir")
193 if ((ildir<1).or.(ildir>self%nl)) call abor1_ftn("qg_fields:dirac invalid ildir")
194 if ((ifdir<1).or.(ifdir>self%nf)) call abor1_ftn("qg_fields:dirac invalid ifdir")
195 
196 ! Setup Diracs
197 call zeros(self)
198 ioff = (ifdir-1)*self%nl
199 do idir=1,ndir
200  self%gfld3d(ixdir(idir),iydir(idir),ioff+ildir) = 1.0
201 end do
202 
203 end subroutine dirac
204 
205 ! ------------------------------------------------------------------------------
206 
207 subroutine random(self)
209 implicit none
210 type(qg_field), intent(inout) :: self
211 
212 call check(self)
213 
214 call random_vector(self%gfld3d(:,:,:))
215 if (self%lbc) then
216  call random_vector(self%xbound(:))
217  call random_vector(self%qbound(:,:))
218 endif
219 
220 end subroutine random
221 
222 ! ------------------------------------------------------------------------------
223 
224 subroutine copy(self,rhs)
225 implicit none
226 type(qg_field), intent(inout) :: self
227 type(qg_field), intent(in) :: rhs
228 integer :: nf
229 
230 call check_resolution(self, rhs)
231 
232 nf = common_vars(self, rhs)
233 self%gfld3d(:,:,1:nf) = rhs%gfld3d(:,:,1:nf)
234 if (self%nf>nf) self%gfld3d(:,:,nf+1:self%nf) = 0.0_kind_real
235 
236 if (self%lbc) then
237  if (rhs%lbc) then
238  self%xbound(:) = rhs%xbound(:)
239  self%qbound(:,:) = rhs%qbound(:,:)
240  else
241  self%xbound(:) = 0.0_kind_real
242  self%qbound(:,:) = 0.0_kind_real
243  endif
244 endif
245 
246 return
247 end subroutine copy
248 
249 ! ------------------------------------------------------------------------------
250 
251 subroutine self_add(self,rhs)
252 implicit none
253 type(qg_field), intent(inout) :: self
254 type(qg_field), intent(in) :: rhs
255 integer :: nf
256 
257 call check_resolution(self, rhs)
258 
259 nf = common_vars(self, rhs)
260 self%gfld3d(:,:,1:nf) = self%gfld3d(:,:,1:nf) + rhs%gfld3d(:,:,1:nf)
261 
262 if (self%lbc .and. rhs%lbc) then
263  self%xbound(:) = self%xbound(:) + rhs%xbound(:)
264  self%qbound(:,:) = self%qbound(:,:) + rhs%qbound(:,:)
265 endif
266 
267 return
268 end subroutine self_add
269 
270 ! ------------------------------------------------------------------------------
271 
272 subroutine self_schur(self,rhs)
273 implicit none
274 type(qg_field), intent(inout) :: self
275 type(qg_field), intent(in) :: rhs
276 integer :: nf
277 
278 call check_resolution(self, rhs)
279 
280 nf = common_vars(self, rhs)
281 self%gfld3d(:,:,1:nf) = self%gfld3d(:,:,1:nf) * rhs%gfld3d(:,:,1:nf)
282 
283 if (self%lbc .and. rhs%lbc) then
284  self%xbound(:) = self%xbound(:) * rhs%xbound(:)
285  self%qbound(:,:) = self%qbound(:,:) * rhs%qbound(:,:)
286 endif
287 
288 return
289 end subroutine self_schur
290 
291 ! ------------------------------------------------------------------------------
292 
293 subroutine self_sub(self,rhs)
294 implicit none
295 type(qg_field), intent(inout) :: self
296 type(qg_field), intent(in) :: rhs
297 integer :: nf
298 
299 call check_resolution(self, rhs)
300 
301 nf = common_vars(self, rhs)
302 self%gfld3d(:,:,1:nf) = self%gfld3d(:,:,1:nf) - rhs%gfld3d(:,:,1:nf)
303 
304 if (self%lbc .and. rhs%lbc) then
305  self%xbound(:) = self%xbound(:) - rhs%xbound(:)
306  self%qbound(:,:) = self%qbound(:,:) - rhs%qbound(:,:)
307 endif
308 
309 return
310 end subroutine self_sub
311 
312 ! ------------------------------------------------------------------------------
313 
314 subroutine self_mul(self,zz)
315 implicit none
316 type(qg_field), intent(inout) :: self
317 real(kind=kind_real), intent(in) :: zz
318 
319 call check(self)
320 
321 self%gfld3d(:,:,:) = zz * self%gfld3d(:,:,:)
322 if (self%lbc) then
323  self%xbound(:) = zz * self%xbound(:)
324  self%qbound(:,:) = zz * self%qbound(:,:)
325 endif
326 
327 return
328 end subroutine self_mul
329 
330 ! ------------------------------------------------------------------------------
331 
332 subroutine axpy(self,zz,rhs)
333 implicit none
334 type(qg_field), intent(inout) :: self
335 real(kind=kind_real), intent(in) :: zz
336 type(qg_field), intent(in) :: rhs
337 integer :: nf
338 
339 call check_resolution(self, rhs)
340 
341 nf = common_vars(self, rhs)
342 self%gfld3d(:,:,1:nf) = self%gfld3d(:,:,1:nf) + zz * rhs%gfld3d(:,:,1:nf)
343 
344 if (self%lbc .and. rhs%lbc) then
345  self%xbound(:) = self%xbound(:) + zz * rhs%xbound(:)
346  self%qbound(:,:) = self%qbound(:,:) + zz * rhs%qbound(:,:)
347 endif
348 
349 return
350 end subroutine axpy
351 
352 ! ------------------------------------------------------------------------------
353 
354 subroutine dot_prod(fld1,fld2,zprod)
355 implicit none
356 type(qg_field), intent(in) :: fld1, fld2
357 real(kind=kind_real), intent(inout) :: zprod
358 
359 integer :: jx,jy,jz,jj
360 real(kind=kind_real), allocatable :: zz(:)
361 
362 call check_resolution(fld1, fld2)
363 if (fld1%nf /= fld2%nf .or. fld1%nl /= fld2%nl) then
364  call abor1_ftn("qg_fields:field_prod error number of fields")
365 endif
366 !if (fld1%lbc .or. fld2%lbc) then
367 ! call abor1_ftn("qg_fields:field_prod should never dot_product full state")
368 !endif
369 
370 allocate(zz(fld1%nl*fld1%nf))
371 zz(:)=0.0_kind_real
372 do jy=1,fld1%geom%ny
373 do jx=1,fld1%geom%nx
374 do jz=1,fld1%nl*fld1%nf
375  zz(jz) = zz(jz) + fld1%gfld3d(jx,jy,jz) * fld2%gfld3d(jx,jy,jz)
376 enddo
377 enddo
378 enddo
379 
380 zprod=0.0_kind_real
381 do jj=1,fld1%nl*fld1%nf
382  zprod=zprod+zz(jj)
383 enddo
384 deallocate(zz)
385 
386 return
387 end subroutine dot_prod
388 
389 ! ------------------------------------------------------------------------------
390 
391 subroutine add_incr(self,rhs)
392 implicit none
393 type(qg_field), intent(inout) :: self
394 type(qg_field), intent(in) :: rhs
395 
396 integer :: i
397 
398 call check(self)
399 call check(rhs)
400 
401 if (self%geom%nx==rhs%geom%nx .and. self%geom%ny==rhs%geom%ny) then
402  do i=1,rhs%nf
403  select case (trim(rhs%fldnames(i)))
404  case ("x")
405  self%x(:,:,:) = self%x(:,:,:) + rhs%x(:,:,:)
406  case ("q")
407  self%q(:,:,:) = self%q(:,:,:) + rhs%q(:,:,:)
408  case ("u")
409  self%u(:,:,:) = self%u(:,:,:) + rhs%u(:,:,:)
410  case ("v")
411  self%v(:,:,:) = self%v(:,:,:) + rhs%v(:,:,:)
412  end select
413  end do
414 else
415  call abor1_ftn("qg_fields:add_incr: not coded for low res increment yet")
416 endif
417 
418 return
419 end subroutine add_incr
420 
421 ! ------------------------------------------------------------------------------
422 
423 subroutine diff_incr(lhs,x1,x2)
424 implicit none
425 type(qg_field), intent(inout) :: lhs
426 type(qg_field), intent(in) :: x1
427 type(qg_field), intent(in) :: x2
428 
429 integer :: i
430 
431 call check(lhs)
432 call check(x1)
433 call check(x2)
434 
435 call zeros(lhs)
436 if (x1%geom%nx==x2%geom%nx .and. x1%geom%ny==x2%geom%ny) then
437  if (lhs%geom%nx==x1%geom%nx .and. lhs%geom%ny==x1%geom%ny) then
438  do i=1,lhs%nf
439  select case (trim(lhs%fldnames(i)))
440  case ("x")
441  lhs%x(:,:,:) = x1%x(:,:,:) - x2%x(:,:,:)
442  case ("q")
443  lhs%q(:,:,:) = x1%q(:,:,:) - x2%q(:,:,:)
444  case ("u")
445  lhs%u(:,:,:) = x1%u(:,:,:) - x2%u(:,:,:)
446  case ("v")
447  lhs%v(:,:,:) = x1%v(:,:,:) - x2%v(:,:,:)
448  end select
449  end do
450  else
451  call abor1_ftn("qg_fields:diff_incr: not coded for low res increment yet")
452  endif
453 else
454  call abor1_ftn("qg_fields:diff_incr: states not at same resolution")
455 endif
456 
457 return
458 end subroutine diff_incr
459 
460 ! ------------------------------------------------------------------------------
461 
462 subroutine change_resol(fld,rhs)
463 implicit none
464 type(qg_field), intent(inout) :: fld
465 type(qg_field), intent(in) :: rhs
466 real(kind=kind_real), allocatable :: ztmp(:,:)
467 real(kind=kind_real) :: dy1, dy2, ya, yb, dx1, dx2, xa, xb
468 integer :: jx, jy, jf, iy, ia, ib
469 
470 call check(fld)
471 call check(rhs)
472 
473 if (fld%geom%nx==rhs%geom%nx .and. fld%geom%ny==rhs%geom%ny) then
474  call copy(fld, rhs)
475 else
476  call abor1_ftn("qg_fields:field_resol: untested code")
477 
478 allocate(ztmp(rhs%geom%nx,rhs%nl*rhs%nf))
479 dy1=1.0_kind_real/real(fld%geom%ny,kind_real)
480 dy2=1.0_kind_real/real(rhs%geom%ny,kind_real)
481 dx1=1.0_kind_real/real(fld%geom%nx,kind_real)
482 dx2=1.0_kind_real/real(rhs%geom%nx,kind_real)
483 do jy=1,fld%geom%ny
484 ! North-south interpolation
485  if (jy==1 .or. jy==fld%geom%ny) then
486  if (jy==1) then
487  iy=1
488  else
489  iy=rhs%geom%ny
490  endif
491  do jx=1,rhs%geom%nx
492  do jf=1,rhs%nl*rhs%nf
493  ztmp(jx,jf)=rhs%gfld3d(jx,iy,jf)
494  enddo
495  enddo
496  else
497  call lin_weights(jy,dy1,dy2,ia,ib,ya,yb)
498  if (ib>rhs%geom%ny) call abor1_ftn("qg_fields:field_resol: ib too large")
499  do jx=1,rhs%geom%nx
500  do jf=1,rhs%nl*rhs%nf
501  ztmp(jx,jf)=ya*rhs%gfld3d(jx,ia,jf)+yb*rhs%gfld3d(jx,ib,jf)
502  enddo
503  enddo
504  endif
505 ! East-west interpolation (periodic)
506  do jx=1,fld%geom%nx
507  call lin_weights(jx,dx1,dx2,ia,ib,xa,xb)
508  if (ib>rhs%geom%nx) ib=ib-rhs%geom%nx
509  do jf=1,fld%nl*rhs%nf
510  fld%gfld3d(jx,jy,jf)=xa*ztmp(jx,jf)+xb*ztmp(jx+1,jf)
511  enddo
512  enddo
513 enddo
514 deallocate(ztmp)
515 
516 endif
517 
518 return
519 end subroutine change_resol
520 
521 ! ------------------------------------------------------------------------------
522 
523 subroutine read_file(fld, c_conf, vdate)
524 ! Needs more interface clean-up here...
525 use iso_c_binding
526 use datetime_mod
527 use fckit_log_module, only : fckit_log
528 
529 implicit none
530 type(qg_field), intent(inout) :: fld !< Fields
531 type(c_ptr), intent(in) :: c_conf !< Configuration
532 type(datetime), intent(inout) :: vdate !< DateTime
533 
534 integer, parameter :: iunit=10
535 integer, parameter :: max_string_length=800 ! Yuk!
536 character(len=max_string_length+50) :: record
537 character(len=max_string_length) :: filename
538 character(len=20) :: sdate, fmtn
539 character(len=4) :: cnx
540 character(len=11) :: fmt1='(X,ES24.16)'
541 character(len=1024) :: buf
542 integer :: ic, iy, il, ix, is, jx, jy, jf, iread, nf
543 integer :: ncid, nx_id, ny_id, nl_id, nc_id, gfld3d_id, xbound_id, qbound_id
544 real(kind=kind_real), allocatable :: zz(:)
545 
546 iread = 1
547 if (config_element_exists(c_conf,"read_from_file")) then
548  iread = config_get_int(c_conf,"read_from_file")
549 endif
550 if (iread==0) then
551  call fckit_log%warning("qg_fields:read_file: Inventing State")
552  call invent_state(fld,c_conf)
553  sdate = config_get_string(c_conf,len(sdate),"date")
554  write(buf,*) 'validity date is: '//sdate
555  call fckit_log%info(buf)
556  call datetime_set(sdate, vdate)
557 else
558  call zeros(fld)
559  filename = config_get_string(c_conf,len(filename),"filename")
560  write(buf,*) 'qg_field:read_file: opening '//filename
561  call fckit_log%info(buf)
562 
563  ! Read data
564  if (netcdfio) then
565 
566  call ncerr(nf90_open(trim(filename)//'.nc',nf90_nowrite,ncid))
567  call ncerr(nf90_inq_dimid(ncid,'nx',nx_id))
568  call ncerr(nf90_inq_dimid(ncid,'ny',ny_id))
569  call ncerr(nf90_inq_dimid(ncid,'nl',nl_id))
570  call ncerr(nf90_inq_dimid(ncid,'nc',nc_id))
571  call ncerr(nf90_inquire_dimension(ncid,nx_id,len=ix))
572  call ncerr(nf90_inquire_dimension(ncid,ny_id,len=iy))
573  call ncerr(nf90_inquire_dimension(ncid,nl_id,len=il))
574  call ncerr(nf90_inquire_dimension(ncid,nc_id,len=ic))
575  if (ix /= fld%geom%nx .or. iy /= fld%geom%ny .or. il /= fld%nl) then
576  write (record,*) "qg_fields:read_file: ", &
577  & "input fields have wrong dimensions: ",ix,iy,il
578  call fckit_log%error(record)
579  write (record,*) "qg_fields:read_file: expected: ",fld%geom%nx,fld%geom%ny,fld%nl
580  call fckit_log%error(record)
581  call abor1_ftn("qg_fields:read_file: input fields have wrong dimensions")
582  endif
583  call ncerr(nf90_get_att(ncid,nf90_global,'lbc',is))
584  call ncerr(nf90_get_att(ncid,nf90_global,'sdate',sdate))
585  write(buf,*) 'validity date is: '//sdate
586  call fckit_log%info(buf)
587  nf = min(fld%nf, ic)
588  call ncerr(nf90_inq_varid(ncid,'gfld3d',gfld3d_id))
589  do jf=1,il*nf
590  call ncerr(nf90_get_var(ncid,gfld3d_id,fld%gfld3d(:,:,jf),(/1,1,jf/),(/ix,iy,1/)))
591  enddo
592  if (fld%lbc) then
593  call ncerr(nf90_inq_varid(ncid,'xbound',xbound_id))
594  call ncerr(nf90_get_var(ncid,xbound_id,fld%xbound))
595  call ncerr(nf90_inq_varid(ncid,'qbound',qbound_id))
596  call ncerr(nf90_get_var(ncid,qbound_id,fld%qbound))
597  endif
598  call ncerr(nf90_close(ncid))
599 
600  else
601 
602  open(unit=iunit, file=trim(filename), form='formatted', action='read')
603 
604  read(iunit,*) ix, iy, il, ic, is
605  if (ix /= fld%geom%nx .or. iy /= fld%geom%ny .or. il /= fld%nl) then
606  write (record,*) "qg_fields:read_file: ", &
607  & "input fields have wrong dimensions: ",ix,iy,il
608  call fckit_log%error(record)
609  write (record,*) "qg_fields:read_file: expected: ",fld%geom%nx,fld%geom%ny,fld%nl
610  call fckit_log%error(record)
611  call abor1_ftn("qg_fields:read_file: input fields have wrong dimensions")
612  endif
613 
614  read(iunit,*) sdate
615  write(buf,*) 'validity date is: '//sdate
616  call fckit_log%info(buf)
617  call datetime_set(sdate, vdate)
618 
619  if (fld%geom%nx>9999) call abor1_ftn("Format too small")
620  write(cnx,'(I4)')fld%geom%nx
621  fmtn='('//trim(cnx)//fmt1//')'
622 
623  nf = min(fld%nf, ic)
624  do jf=1,il*nf
625  do jy=1,fld%geom%ny
626  read(iunit,fmtn) (fld%gfld3d(jx,jy,jf), jx=1,fld%geom%nx)
627  enddo
628  enddo
629 ! Skip un-necessary data from file if any
630  allocate(zz(fld%geom%nx))
631  do jf=nf*il+1, ic*il
632  do jy=1,fld%geom%ny
633  read(iunit,fmtn) (zz(jx), jx=1,fld%geom%nx)
634  enddo
635  enddo
636  deallocate(zz)
637 
638  if (fld%lbc) then
639  do jf=1,4
640  read(iunit,fmt1) fld%xbound(jf)
641  enddo
642  do jf=1,4
643  read(iunit,fmtn) (fld%qbound(jx,jf), jx=1,fld%geom%nx)
644  enddo
645  endif
646 
647  close(iunit)
648 
649  endif
650 
651  ! Set date
652  call datetime_set(sdate, vdate)
653 endif
654 
655 call check(fld)
656 
657 return
658 end subroutine read_file
659 
660 ! ------------------------------------------------------------------------------
661 !> Analytic Initialization for the QG model
662 !!
663 !! \details **analytic_init()** initializes the qg field using one of several alternative idealized analytic models.
664 !! This is intended to faciltitate testing by eliminating the need to read in the initial state
665 !! from a file and by providing exact expressions to test interpolations.
666 !! This function is activated by setting the initial.analytic_init field in the configuration file.
667 !!
668 !! Initialization options that begin with "dcmip" refer to tests defined by the multi-institutional
669 !! 2012 [Dynamical Core Intercomparison Project](https://earthsystealcmcog.org/projects/dcmip-2012)
670 !! and the associated Summer School, sponsored by NOAA, NSF, DOE, NCAR, and the University of Michigan.
671 !!
672 !! Currently implemented options for analytic_init include:
673 !! * baroclinic-instability: A two-layer flow that is baroclinically unstable in the presence of non-zero orography
674 !! * dcmip-test-1-1: 3D deformational flow
675 !! * dcmip-test-1-2: 3D Hadley-like meridional circulation
676 !!
677 !! Relevant parameters specified in the **State.StateGenerate** section of the config file include:
678 !! * **analytic_init** the type of initialization as described in analytic_init())
679 !! * **variables** currently must be set to ["x","q","u","v"]
680 !! * **date** a reference date and time for the state
681 !! * **top_layer_depth**, **bottom_layer_depth** are needed in order to convert the normalized height
682 !! coordinate into meters so it can be used in the analytic formulae
683 !!
684 !! \author M. Miesch (JCSDA, adapted from a pre-existing call to invent_state)
685 !! \date March 7, 2018: Created
686 !!
687 !! \warning If you use the dcmip routines, be sure to include u and v in the variables list.
688 !!
689 !! \warning For dcmip initial conditions, this routine computes the streamfunction x and the potential
690 !! vorticity q from the horizontal winds u and v. Since q (or alternatively x) is the state variable
691 !! for the evolution of the QG model, only the non-divergent (vortical) component of the horizontal
692 !! flow is captured. In other words, u and v are projected onto a flow field with zero horizontal
693 !! divergence. Furthermore, this projection neglects geometric curvature factors. This projection
694 !! is used to calculate the streamfunction X and the potential vorticity q. However, on exiting this
695 !! function, the u and v components of the qg_field structure are still set to their original
696 !! (non-projected) values. This is for use with the State interpolation test. The winds u and v
697 !! are re-calculated from X before doing a forecast by the routine c_qg_prepare_integration() in
698 !! c_qg_model.F90.
699 !!
700 !! \warning For all but the baroclinic-instability option, the PV here is computed assuming zero
701 !! orography. For particular model configurations, the orography is defined in c_qg_setup()
702 !! [c_qg_model.F90] and the PV is recalculated in c_qg_prepare_integration() [c_qg_model.F90]
703 !! before the integration of the model commences.
704 !!
705 
706 subroutine analytic_init(fld, geom, config, vdate)
708  use iso_c_binding
709  use datetime_mod
710  use fckit_log_module, only : fckit_log
712  use qg_constants
713 
714  implicit none
715  type(qg_field), intent(inout) :: fld !< Fields
716  type(qg_geom), intent(inout) :: geom !< Grid information
717  type(c_ptr), intent(in) :: config !< Configuration
718  type(datetime), intent(inout) :: vdate !< DateTime
719 
720  character(len=30) :: ic
721  character(len=20) :: sdate
722  character(len=1024) :: buf
723  real(kind=kind_real) :: d1, d2, height(2), z, f1, f2, xdum(2)
724  real(kind=kind_real) :: deltax,deltay,deg_to_rad,rlat,rlon,xx,yy,kx,ky
725  real(kind=kind_real) :: latrange, lonrange, sclx, scly
726  real(kind=kind_real) :: p0,u0,v0,w0,t0,phis0,ps0,rho0,hum0,q1,q2,q3,q4
727  real(kind=kind_real), allocatable :: rs(:,:)
728  integer :: ix, iy, il
729 
730  if (config_element_exists(config,"analytic_init")) then
731  ic = trim(config_get_string(config,len(ic),"analytic_init"))
732  else
733  ! this is mainly for backward compatibility
734  ic = "baroclinic-instability"
735  endif
736 
737  call fckit_log%warning("qg_fields:analytic_init: "//ic)
738  sdate = config_get_string(config,len(sdate),"date")
739  write(buf,*) 'validity date is: '//sdate
740  call fckit_log%info(buf)
741  call datetime_set(sdate,vdate)
742 
743  ! To use the DCMIP routines we need a vertical coordinate
744  ! assume 2 levels for now but easily to generalize as needed
745  d1 = config_get_real(config,"top_layer_depth")
746  d2 = config_get_real(config,"bottom_layer_depth")
747 
748  height(2) = 0.5_kind_real*d2
749  height(1) = d2 + 0.5_kind_real*d1
750  xdum(:) = 0.0_kind_real
751 
752  deltax = domain_zonal/(scale_length*real(geom%nx,kind_real))
753  deltay = domain_meridional/(scale_length*real(geom%ny,kind_real))
754 
757 
758  allocate(rs(geom%nx,geom%ny))
759  rs = 0.0_kind_real
760 
761  deg_to_rad = pi/180.0_kind_real
762 
763  !--------------------------------------
764  init_option: select case (ic)
765 
766  case ("baroclinic-instability")
767  call invent_state(fld,config)
768 
769  case ("large-vortices")
770 
771  latrange = geom%lat(geom%ny) - geom%lat(1)
772  lonrange = geom%lon(geom%nx) - geom%lon(1)
773  if (geom%lon(geom%nx) < geom%lon(1)) lonrange=lonrange+360.0_kind_real
774 
775  ! In interp_tl, the effective grid spacing is assumed to be dx = 1/nx
776  ! similarly for dy. This is a scale factor to take this into account
777  sclx = (geom%nx-1.0_kind_real)/geom%nx
778  scly = (geom%ny-1.0_kind_real)/geom%ny
779 
780  kx = pi
781  ky = 2.0_kind_real * pi
782 
783  do il = 1, fld%nl
784  z = height(il)
785  do iy = 1,fld%geom%ny ; do ix = 1, fld%geom%nx
786  ! convert lat and lon to normalized x,y coordinate between 0 and 1
787  xx = sclx*(geom%lon(ix)-geom%lon(1))/lonrange
788  if (geom%lon(ix) < geom%lon(1)) xx=xx+sclx*360.0_kind_real/lonrange
789  yy = scly*(geom%lat(iy)-geom%lat(1))/latrange
790 
791  fld%x(ix,iy,il) = sin(kx*xx)*sin(ky*yy)
792  fld%u(ix,iy,il) = -ky*sin(kx*xx)*cos(ky*yy)
793  fld%v(ix,iy,il) = kx*cos(kx*xx)*sin(ky*yy)
794 
795  enddo; enddo
796  enddo
797 
798  if (fld%lbc) then
799  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,fld%x_north,fld%x_south,&
800  f1,f2,deltax,deltay,bet,rs,fld%lbc)
801  else
802  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,xdum,xdum,&
803  f1,f2,deltax,deltay,bet,rs,fld%lbc)
804  endif
805 
806  case ("dcmip-test-1-1")
807 
808  do il = 1, fld%nl
809  z = height(il)
810  do iy = 1,fld%geom%ny ; do ix = 1, fld%geom%nx
811 
812  ! convert lat and lon to radians
813  rlat = deg_to_rad * geom%lat(iy)
814  rlon = deg_to_rad*modulo(geom%lon(ix)+180.0_kind_real,360.0_kind_real) - pi
815 
816  call test1_advection_deformation(rlon,rlat,p0,z,1,&
817  u0,v0,w0,t0,phis0,ps0,rho0,hum0,q1,q2,q3,q4)
818 
819  fld%u(ix,iy,il) = u0 / ubar
820  fld%v(ix,iy,il) = v0 / ubar
821 
822  enddo; enddo
823  enddo
824 
825  call calc_streamfunction(geom%nx,geom%ny,fld%x,fld%u,fld%v,deltax,deltay)
826 
827  ! Some compilers don't tolerate passing a null pointer
828  if (fld%lbc) then
829  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,fld%x_north,fld%x_south,&
830  f1,f2,deltax,deltay,bet,rs,fld%lbc)
831  else
832  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,xdum,xdum,&
833  f1,f2,deltax,deltay,bet,rs,fld%lbc)
834  endif
835 
836  case ("dcmip-test-1-2")
837 
838  do il = 1, fld%nl
839  z = height(il)
840  do iy = 1,fld%geom%ny ; do ix = 1, fld%geom%nx
841 
842  ! convert lat and lon to radians
843  rlat = deg_to_rad * geom%lat(iy)
844  rlon = deg_to_rad*modulo(geom%lon(ix)+180.0_kind_real,360.0_kind_real) - pi
845 
846  call test1_advection_hadley(rlon,rlat,p0,z,1,&
847  u0,v0,w0,t0,phis0,ps0,rho0,hum0,q1)
848 
849  fld%u(ix,iy,il) = u0 / ubar
850  fld%v(ix,iy,il) = v0 / ubar
851 
852  enddo; enddo
853  enddo
854 
855  call calc_streamfunction(geom%nx,geom%ny,fld%x,fld%u,fld%v,deltax,deltay)
856 
857  ! Some compilers don't tolerate passing a null pointer
858  if (fld%lbc) then
859  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,fld%x_north,fld%x_south,&
860  f1,f2,deltax,deltay,bet,rs,fld%lbc)
861  else
862  call calc_pv(geom%nx,geom%ny,fld%q,fld%x,xdum,xdum,&
863  f1,f2,deltax,deltay,bet,rs,fld%lbc)
864  endif
865 
866  case default
867 
868  call abor1_ftn ("qg_fields:analytic_init not properly defined")
869 
870  end select init_option
871 
872  !--------------------------------------
873 
874  call check(fld)
875 
876  return
877 
878 end subroutine analytic_init
879 
880 ! ------------------------------------------------------------------------------
881 !> Calculate Streamfunction from u and v
882 !!
883 !! \details **calc_streamfunction()** computes the streamfunction x from the velocities u and v.
884 !! It was originally developed to support the dcmip initial conditions in analytic_init()
885 !! but is potentially of broader applicability.
886 !! The algorithm first computes the vertical vorticity and then inverts the
887 !! resulting Laplacian for x.
888 !!
889 !! \author M. Miesch
890 !! \date March 7, 2018: Created
891 !!
892 !! \warning This routine currently does not take into account latitudinal boundary conditions on x.
893 
894 subroutine calc_streamfunction(kx,ky,x,u,v,dx,dy)
896  integer, intent(in) :: kx !< Zonal grid dimension
897  integer, intent(in) :: ky !< Meridional grid dimension
898  real(kind=kind_real), intent(out) :: x(kx,ky,2) !< Streamfunction
899  real(kind=kind_real), intent(in) :: u(kx,ky,2) !< zonal velocity (non-dimensional)
900  real(kind=kind_real), intent(in) :: v(kx,ky,2) !< meridional velocity (non-dimensional)
901  real(kind=kind_real), intent(in) :: dx !< Zonal grid spacing (non-dimensional)
902  real(kind=kind_real), intent(in) :: dy !< Meridional grid spacing (non-dimensional)
903 
904  real(kind=kind_real), allocatable :: vort(:,:), psi(:,:)
905  real(kind=kind_real), allocatable :: dudy(:), dvdx(:)
906  integer :: ix, iy, il
907 
908  allocate(vort(kx,ky),psi(kx,ky))
909  allocate(dudy(ky),dvdx(kx))
910 
911  ! assume two levels - easy to generalize if needed
912  do il = 1, 2
913 
914  ! compute vertical vorticity from u and v
915  do iy=1,ky
916  call deriv_1d(dvdx,v(:,iy,il),kx,dx,periodic=.true.)
917  vort(:,iy) = dvdx
918  enddo
919 
920  do ix=1,kx
921  call deriv_1d(dudy,u(ix,:,il),ky,dy)
922  vort(ix,:) = vort(ix,:) - dudy
923  enddo
924 
925  ! invert the Laplacian to get the streamfunction
926  call solve_helmholz(psi,vort,0.0_kind_real,kx,ky,dx,dy)
927  x(:,:,il) = psi
928 
929  enddo
930 
931  deallocate(vort,psi,dudy,dvdx)
932 
933 end subroutine calc_streamfunction
934 
935 ! ------------------------------------------------------------------------------
936 !> Finite Difference Derivative
937 !!
938 !! \details **deriv()** computes the first derivative of a function using a simple
939 !! fourth-order, central-difference scheme
940 !!
941 !! \author M. Miesch
942 !! \date March 7, 2018: Created
943 
944 subroutine deriv_1d(df,f,n,delta,periodic)
945 
946  real(kind=kind_real), intent(In) :: f(:) !< 1D function
947  real(kind=kind_real), intent(In) :: delta !< grid spacing (assumed uniform)
948  Integer, intent(In) :: n !< Number of grid points
949  real(kind=kind_real), intent(InOut) :: df(:) !< result
950  logical, optional, intent(In) :: periodic !< Set to true if the domain is periodic
951 
952  integer :: i
953  real(kind=kind_real) :: ho2, ho12
954  logical :: wrap
955 
956  if (present(periodic)) then
957  wrap=periodic
958  else
959  wrap=.false.
960  endIf
961 
962  ho2 = 1.0_kind_real/(2.0_kind_real*delta)
963  ho12 = 1.0_kind_real/(12.0_kind_real*delta)
964 
965  ! interior points
966  do i=3,n-2
967  df(i) = ho12*(f(i-2)-8.0_kind_real*f(i-1)+8.0_kind_real*f(i+1)-f(i+2))
968  enddo
969 
970  if (wrap) then
971 
972  df(1) = ho12*(f(n-1)-8.0_kind_real*f(n)+8.0_kind_real*f(2)-f(3))
973  df(2) = ho12*(f(n)-8.0_kind_real*f(1)+8.0_kind_real*f(3)-f(4))
974  df(n-1) = ho12*(f(n-3)-8.0_kind_real*f(n-2)+8.0_kind_real*f(n)-f(1))
975  df(n) = ho12*(f(n-2)-8.0_kind_real*f(n-1)+8.0_kind_real*f(1)-f(2))
976 
977  else
978 
979  ! left edge (lower order)
980  df(1) = ho2*(-3.0_kind_real*f(1)+4.0_kind_real*f(2)-f(3))
981  df(2) = ho12*(-3.0_kind_real*f(1)-10.0_kind_real*f(2)+18.0_kind_real*f(3)-6.0_kind_real*f(4)+f(5))
982 
983  ! right edge (lower order)
984  df(n-1) = ho12*(3.0_kind_real*f(n)+10.0_kind_real*f(n-1)-18.0_kind_real*f(n-2)+6.0_kind_real*f(n-3)-f(n-4))
985  df(n) = ho2*(3.0_kind_real*f(n)-4.0_kind_real*f(n-1)+f(n-2))
986 
987  endIf
988 
989 end subroutine deriv_1d
990 
991 ! ------------------------------------------------------------------------------
992 
993 subroutine write_file(fld, c_conf, vdate)
994 use iso_c_binding
995 use datetime_mod
996 use fckit_log_module, only : fckit_log
997 
998 implicit none
999 type(qg_field), intent(in) :: fld !< Fields
1000 type(c_ptr), intent(in) :: c_conf !< Configuration
1001 type(datetime), intent(in) :: vdate !< DateTime
1002 
1003 integer, parameter :: iunit=11
1004 integer, parameter :: max_string_length=800 ! Yuk!
1005 integer :: ncid, nx_id, ny_id, nl_id, nc_id, ntot_id, four_id, gfld3d_id, xbound_id, qbound_id
1006 character(len=max_string_length+50) :: record
1007 character(len=max_string_length) :: filename
1008 character(len=20) :: sdate, fmtn
1009 character(len=4) :: cnx
1010 character(len=11) :: fmt1='(X,ES24.16)'
1011 character(len=1024):: buf
1012 integer :: jf, jy, jx, is
1013 
1014 call check(fld)
1015 
1016 filename = genfilename(c_conf,max_string_length,vdate)
1017 WRITE(buf,*) 'qg_field:write_file: writing '//filename
1018 call fckit_log%info(buf)
1019 
1020 is=0
1021 if (fld%lbc) is=1
1022 call datetime_to_string(vdate, sdate)
1023 
1024 if (netcdfio) then
1025 
1026  call ncerr(nf90_create(trim(filename)//'.nc',or(nf90_clobber,nf90_64bit_offset),ncid))
1027  call ncerr(nf90_def_dim(ncid,'nx',fld%geom%nx,nx_id))
1028  call ncerr(nf90_def_dim(ncid,'ny',fld%geom%ny,ny_id))
1029  call ncerr(nf90_def_dim(ncid,'nl',fld%nl,nl_id))
1030  call ncerr(nf90_def_dim(ncid,'nc',fld%nf,nc_id))
1031  call ncerr(nf90_def_dim(ncid,'ntot',fld%nl*fld%nf,ntot_id))
1032  call ncerr(nf90_def_dim(ncid,'four',4,four_id))
1033  call ncerr(nf90_put_att(ncid,nf90_global,'lbc',is))
1034 
1035  call ncerr(nf90_put_att(ncid,nf90_global,'sdate',sdate))
1036  call ncerr(nf90_def_var(ncid,'gfld3d',nf90_double,(/nx_id,ny_id,ntot_id/),gfld3d_id))
1037 
1038  if (fld%lbc) then
1039  call ncerr(nf90_def_var(ncid,'xbound',nf90_double,(/four_id/),xbound_id))
1040  call ncerr(nf90_def_var(ncid,'qbound',nf90_double,(/nx_id,four_id/),qbound_id))
1041  end if
1042 
1043  call ncerr(nf90_enddef(ncid))
1044 
1045  call ncerr(nf90_put_var(ncid,gfld3d_id,fld%gfld3d))
1046 
1047  if (fld%lbc) then
1048  call ncerr(nf90_put_var(ncid,xbound_id,fld%xbound))
1049  call ncerr(nf90_put_var(ncid,qbound_id,fld%qbound))
1050  end if
1051 
1052  call ncerr(nf90_close(ncid))
1053 
1054 else
1055 
1056  open(unit=iunit, file=trim(filename), form='formatted', action='write')
1057 
1058  write(iunit,*) fld%geom%nx, fld%geom%ny, fld%nl, fld%nf, is
1059  write(iunit,*) sdate
1060 
1061  if (fld%geom%nx>9999) call abor1_ftn("Format too small")
1062  write(cnx,'(I4)')fld%geom%nx
1063  fmtn='('//trim(cnx)//fmt1//')'
1064 
1065  do jf=1,fld%nl*fld%nf
1066  do jy=1,fld%geom%ny
1067  write(iunit,fmtn) (fld%gfld3d(jx,jy,jf), jx=1,fld%geom%nx)
1068  enddo
1069  enddo
1070 
1071  if (fld%lbc) then
1072  do jf=1,4
1073  write(iunit,fmt1) fld%xbound(jf)
1074  enddo
1075  do jf=1,4
1076  write(iunit,fmtn) (fld%qbound(jx,jf), jx=1,fld%geom%nx)
1077  enddo
1078  endif
1079 
1080  close(iunit)
1081 endif
1082 
1083 return
1084 end subroutine write_file
1085 
1086 ! ------------------------------------------------------------------------------
1087 
1088 subroutine gpnorm(fld, nf, pstat)
1089 implicit none
1090 type(qg_field), intent(in) :: fld
1091 integer, intent(in) :: nf
1092 real(kind=kind_real), intent(inout) :: pstat(3, nf)
1093 integer :: jj,joff
1094 
1095 call check(fld)
1096 
1097 do jj=1,fld%nf
1098  joff=(jj-1)*fld%nl
1099  pstat(1,jj)=minval(fld%gfld3d(:,:,joff+1:joff+fld%nl))
1100  pstat(2,jj)=maxval(fld%gfld3d(:,:,joff+1:joff+fld%nl))
1101  pstat(3,jj)=sqrt(sum(fld%gfld3d(:,:,joff+1:joff+fld%nl)**2) &
1102  & /real(fld%nl*fld%geom%nx*fld%geom%ny,kind_real))
1103 enddo
1104 jj=jj-1
1105 
1106 if (fld%lbc) then
1107  jj=jj+1
1108  pstat(1,jj)=minval(fld%xbound(:))
1109  pstat(2,jj)=maxval(fld%xbound(:))
1110  pstat(3,jj)=sqrt(sum(fld%xbound(:)**2)/real(4,kind_real))
1111 
1112  jj=jj+1
1113  pstat(1,jj)=minval(fld%qbound(:,:))
1114  pstat(2,jj)=maxval(fld%qbound(:,:))
1115  pstat(3,jj)=sqrt(sum(fld%qbound(:,:)**2)/real(4*fld%geom%nx,kind_real))
1116 endif
1117 
1118 if (jj /= nf) call abor1_ftn("qg_fields_gpnorm: error number of fields")
1119 
1120 return
1121 end subroutine gpnorm
1122 
1123 ! ------------------------------------------------------------------------------
1124 
1125 subroutine fldrms(fld, prms)
1126 implicit none
1127 type(qg_field), intent(in) :: fld
1128 real(kind=kind_real), intent(out) :: prms
1129 integer :: jf,jy,jx,ii
1130 real(kind=kind_real) :: zz
1131 
1132 call check(fld)
1133 
1134 zz = 0.0
1135 ii = 0
1136 
1137 do jf=1,fld%nl !*fld%nf
1138  do jy=1,fld%geom%ny
1139  do jx=1,fld%geom%nx
1140  zz = zz + fld%gfld3d(jx,jy,jf)*fld%gfld3d(jx,jy,jf)
1141  enddo
1142  enddo
1143  ii = ii + fld%geom%nx * fld%geom%ny
1144 enddo
1145 
1146 if (fld%lbc) then
1147  do jf=1,4
1148  zz = zz + fld%xbound(jf)*fld%xbound(jf)
1149  enddo
1150  ii = ii + 4
1151  do jf=1,4
1152  do jx=1,fld%geom%nx
1153  zz = zz + fld%qbound(jx,jf)*fld%qbound(jx,jf)
1154  enddo
1155  enddo
1156  ii = ii + 4*fld%geom%nx
1157 endif
1158 
1159 prms = sqrt(zz/real(ii,kind_real))
1160 
1161 end subroutine fldrms
1162 
1163 ! ------------------------------------------------------------------------------
1164 
1165 subroutine interp_tl(fld, locs, vars, gom)
1166 implicit none
1167 type(qg_field), intent(in) :: fld
1168 type(qg_locs), intent(in) :: locs
1169 type(qg_vars), intent(in) :: vars
1170 type(qg_goms), intent(inout) :: gom
1171 real(kind=kind_real) :: di, dj, ai, aj, valb, valt
1172 integer :: jloc,joff,jvar,ii,jj,kk,iright,jsearch
1173 character(len=1) :: cvar
1174 
1175 call check(fld)
1176 
1177 do jloc=1,locs%nloc
1178 ! Convert horizontal coordinate stored in ODB to grid locations
1179  di=locs%xyz(1,jloc)*real(fld%geom%nx,kind_real)
1180  ii=int(di)
1181  ai=di-real(ii,kind_real);
1182  ii=ii+1
1183  if (ii<1.or.ii>fld%geom%nx) call abor1_ftn("qg_fields_interp_tl: error ii")
1184  iright=ii+1
1185  if (iright==fld%geom%nx+1) iright=1
1186 
1187  dj=locs%xyz(2,jloc)*real(fld%geom%ny,kind_real)
1188  jj=int(dj)
1189  aj=dj-real(jj,kind_real);
1190  jj=jj+1
1191  if (jj<1.or.jj>fld%geom%ny) call abor1_ftn("qg_fields_interp_tl: error jj")
1192 
1193  kk=nint(locs%xyz(3,jloc))
1194 
1195 ! Loop on required variables
1196  gom%used=gom%used+1
1197  if (vars%nv/=gom%nvar) call abor1_ftn ("qg_fields_interp_tl: inconsistent var and gom")
1198  do jvar=1,vars%nv
1199  cvar=vars%fldnames(jvar)
1200  joff=-1
1201  do jsearch=1,fld%nf
1202  if (fld%fldnames(jsearch)==cvar) joff=jsearch-1
1203  enddo
1204  if (joff<0) call abor1_ftn("qg_fields_interp_tl: unknown variable")
1205  joff=fld%nl*joff
1206 
1207 ! Interpolate east-west
1208  if (jj>1) then
1209  valb=(1.0_kind_real-ai)*fld%gfld3d(ii ,jj,joff+kk) &
1210  & +ai *fld%gfld3d(iright,jj,joff+kk)
1211  else
1212  select case (cvar)
1213  case ("x")
1214  valb=0.0_kind_real
1215  case ("u")
1216  valb=2.0_kind_real*( (1.0_kind_real-ai)*fld%gfld3d(ii,1,joff+kk) &
1217  & +ai *fld%gfld3d(iright,1,joff+kk) ) &
1218  & - ( (1.0_kind_real-ai)*fld%gfld3d(ii,2,joff+kk) &
1219  & +ai *fld%gfld3d(iright,2,joff+kk) )
1220  case ("v")
1221  valb=0.0_kind_real
1222  end select
1223  endif
1224 
1225  if (jj<fld%geom%ny) then
1226  valt=(1.0_kind_real-ai)*fld%gfld3d(ii ,jj+1,joff+kk) &
1227  & +ai *fld%gfld3d(iright,jj+1,joff+kk)
1228  else
1229  select case (cvar)
1230  case ("x")
1231  valt = 0.0_kind_real
1232  case ("u")
1233  valt=2.0_kind_real*( (1.0_kind_real-ai)*fld%gfld3d(ii,fld%geom%ny,joff+kk) &
1234  & +ai *fld%gfld3d(iright,fld%geom%ny,joff+kk) ) &
1235  & - ( (1.0_kind_real-ai)*fld%gfld3d(ii,fld%geom%ny-1,joff+kk) &
1236  & +ai *fld%gfld3d(iright,fld%geom%ny-1,joff+kk) )
1237  case ("v")
1238  valt = 0.0_kind_real
1239  end select
1240  endif
1241 
1242 ! Interpolate north-south
1243  gom%values(jvar,gom%used) = (1.0_kind_real-aj)*valb + aj*valt
1244  enddo
1245 enddo
1246 
1247 return
1248 end subroutine interp_tl
1249 
1250 ! ------------------------------------------------------------------------------
1251 
1252 subroutine interp_ad(fld, locs, vars, gom)
1253 implicit none
1254 type(qg_field), intent(inout) :: fld
1255 type(qg_locs), intent(in) :: locs
1256 type(qg_vars), intent(in) :: vars
1257 type(qg_goms), intent(inout) :: gom
1258 real(kind=kind_real) :: di, dj, ai, aj, valb, valt
1259 integer :: jloc,joff,jvar,ii,jj,kk,iright,jsearch
1260 character(len=1) :: cvar
1261 
1262 call check(fld)
1263 
1264 do jloc=locs%nloc,1,-1
1265 ! Convert horizontal coordinate stored in ODB to grid locations
1266  di=locs%xyz(1,jloc)*real(fld%geom%nx,kind_real)
1267  ii=int(di)
1268  ai=di-real(ii,kind_real);
1269  ii=ii+1
1270  if (ii<1.or.ii>fld%geom%nx) call abor1_ftn("qg_fields_interp_ad: error ii")
1271  iright=ii+1
1272  if (iright==fld%geom%nx+1) iright=1
1273 
1274  dj=locs%xyz(2,jloc)*real(fld%geom%ny,kind_real)
1275  jj=int(dj)
1276  aj=dj-real(jj,kind_real);
1277  jj=jj+1
1278  if (jj<1.or.jj>fld%geom%ny) call abor1_ftn("qg_fields_interp_ad: error jj")
1279 
1280  kk=nint(locs%xyz(3,jloc))
1281 
1282 ! Loop on required variables
1283  gom%used=gom%used+1
1284  if (vars%nv/=gom%nvar) call abor1_ftn ("qg_fields_interp_tl: inconsistent var and gom")
1285  do jvar=vars%nv,1,-1
1286  cvar=vars%fldnames(jvar)
1287  joff=-1
1288  do jsearch=1,fld%nf
1289  if (fld%fldnames(jsearch)==cvar) joff=jsearch-1
1290  enddo
1291  if (joff<0) call abor1_ftn("qg_fields_interp_ad: unknown variable")
1292  joff=fld%nl*joff
1293 
1294 ! Interpolate north-south
1295  valb = (1.0_kind_real-aj)*gom%values(jvar,gom%nobs-gom%used+1)
1296  valt = aj*gom%values(jvar,gom%nobs-gom%used+1)
1297 
1298 ! Interpolate east-west
1299  if (jj>1) then
1300  fld%gfld3d(ii ,jj,joff+kk) = &
1301  & fld%gfld3d(ii ,jj,joff+kk)+(1.0_kind_real-ai)*valb
1302  fld%gfld3d(iright,jj,joff+kk) = &
1303  & fld%gfld3d(iright,jj,joff+kk)+ai*valb
1304  else
1305  select case (cvar)
1306  case ("u")
1307  fld%gfld3d(ii,1,joff+kk) = &
1308  & fld%gfld3d(ii,1,joff+kk)+2.0_kind_real*(1.0_kind_real-ai)*valb
1309  fld%gfld3d(iright,1,joff+kk) = &
1310  & fld%gfld3d(iright,1,joff+kk)+2.0_kind_real*ai*valb
1311  fld%gfld3d(ii,2,joff+kk) = &
1312  & fld%gfld3d(ii,2,joff+kk)-(1.0_kind_real-ai)*valb
1313  fld%gfld3d(iright,2,joff+kk) = &
1314  & fld%gfld3d(iright,2,joff+kk)-ai*valb
1315  end select
1316  endif
1317 
1318  if (jj<fld%geom%ny) then
1319  fld%gfld3d(ii ,jj+1,joff+kk) = &
1320  & fld%gfld3d(ii ,jj+1,joff+kk)+(1.0_kind_real-ai)*valt
1321  fld%gfld3d(iright,jj+1,joff+kk) = &
1322  & fld%gfld3d(iright,jj+1,joff+kk)+ai*valt
1323  else
1324  select case (cvar)
1325  case ("u")
1326  fld%gfld3d(ii,fld%geom%ny,joff+kk) = &
1327  & fld%gfld3d(ii,fld%geom%ny,joff+kk)+2.0_kind_real*(1.0_kind_real-ai)*valt
1328  fld%gfld3d(iright,fld%geom%ny,joff+kk) = &
1329  & fld%gfld3d(iright,fld%geom%ny,joff+kk)+2.0_kind_real*ai*valt
1330  fld%gfld3d(ii,fld%geom%ny-1,joff+kk) = &
1331  & fld%gfld3d(ii,fld%geom%ny-1,joff+kk)-(1.0_kind_real-ai)*valt
1332  fld%gfld3d(iright,fld%geom%ny-1,joff+kk)= &
1333  & fld%gfld3d(iright,fld%geom%ny-1,joff+kk)-ai*valt
1334  end select
1335  endif
1336  enddo
1337 enddo
1338 
1339 return
1340 end subroutine interp_ad
1341 
1342 ! ------------------------------------------------------------------------------
1343 
1344 subroutine lin_weights(kk,delta1,delta2,k1,k2,w1,w2)
1345 implicit none
1346 integer, intent(in) :: kk
1347 real(kind=kind_real), intent(in) :: delta1,delta2
1348 integer, intent(out) :: k1,k2
1349 real(kind=kind_real), intent(out) :: w1,w2
1350 
1351 integer :: ii
1352 real(kind=kind_real) :: zz
1353 
1354 zz=real(kk-1,kind_real)*delta1
1355 zz=zz/delta2
1356 ii=int(zz)
1357 w1=zz-real(ii,kind_real)
1358 w2=1.0_kind_real-w1
1359 k1=ii+1
1360 k2=ii+2
1361 
1362 return
1363 end subroutine lin_weights
1364 
1365 ! ------------------------------------------------------------------------------
1366 
1367 subroutine ug_size(self, ug)
1369 implicit none
1370 type(qg_field), intent(in) :: self
1371 type(unstructured_grid), intent(inout) :: ug
1372 integer :: igrid
1373 
1374 ! Set number of grids
1375 if (ug%colocated==1) then
1376  ! Colocatd
1377  ug%ngrid = 1
1378 else
1379  ! Not colocated
1380  ug%ngrid = 1
1381 end if
1382 
1383 ! Allocate grid instances
1384 if (.not.allocated(ug%grid)) allocate(ug%grid(ug%ngrid))
1385 
1386 if (ug%colocated==1) then
1387  ! Colocated
1388 
1389  ! Set local number of points
1390  ug%grid(1)%nmga = self%geom%nx*self%geom%ny
1391 
1392  ! Set number of levels
1393  ug%grid(1)%nl0 = self%nl
1394 
1395  ! Set number of variables
1396  ug%grid(1)%nv = self%nf
1397 
1398  ! Set number of timeslots
1399  ug%grid(1)%nts = 1
1400 else
1401  ! Not colocated
1402  do igrid=1,ug%ngrid
1403  ! Set local number of points
1404  ug%grid(igrid)%nmga = self%geom%nx*self%geom%ny
1405 
1406  ! Set number of levels
1407  ug%grid(igrid)%nl0 = self%nl
1408 
1409  ! Set number of variables
1410  ug%grid(igrid)%nv = self%nf
1411 
1412  ! Set number of timeslots
1413  ug%grid(igrid)%nts = 1
1414  enddo
1415 end if
1416 
1417 end subroutine ug_size
1418 
1419 ! ------------------------------------------------------------------------------
1420 
1421 subroutine ug_coord(self, ug, colocated)
1423 implicit none
1424 type(qg_field), intent(in) :: self
1425 type(unstructured_grid), intent(inout) :: ug
1426 integer, intent(in) :: colocated
1427 
1428 integer :: igrid,imga,jx,jy,jl
1429 
1430 ! Copy colocated
1431 ug%colocated = colocated
1432 
1433 ! Define size
1434 call ug_size(self, ug)
1435 
1436 ! Allocate unstructured grid coordinates
1438 
1439 ! Define coordinates
1440 if (ug%colocated==1) then
1441  ! Colocated
1442  imga = 0
1443  do jy=1,self%geom%ny
1444  do jx=1,self%geom%nx
1445  imga = imga+1
1446  ug%grid(1)%lon(imga) = self%geom%lon(jx)
1447  ug%grid(1)%lat(imga) = self%geom%lat(jy)
1448  ug%grid(1)%area(imga) = self%geom%area(jx,jy)
1449  do jl=1,self%nl
1450  ug%grid(1)%vunit(imga,jl) = real(jl,kind=kind_real)
1451  ug%grid(1)%lmask(imga,jl) = .true.
1452  enddo
1453  enddo
1454  enddo
1455 else
1456  ! Not colocated
1457  do igrid=1,ug%ngrid
1458  imga = 0
1459  do jy=1,self%geom%ny
1460  do jx=1,self%geom%nx
1461  imga = imga+1
1462  ug%grid(igrid)%lon(imga) = self%geom%lon(jx)
1463  ug%grid(igrid)%lat(imga) = self%geom%lat(jy)
1464  ug%grid(igrid)%area(imga) = self%geom%area(jx,jy)
1465  do jl=1,self%nl
1466  ug%grid(igrid)%vunit(imga,jl) = real(jl,kind=kind_real)
1467  ug%grid(igrid)%lmask(imga,jl) = .true.
1468  enddo
1469  enddo
1470  enddo
1471  enddo
1472 endif
1473 
1474 end subroutine ug_coord
1475 
1476 ! ------------------------------------------------------------------------------
1477 
1478 subroutine field_to_ug(self, ug, colocated)
1480 implicit none
1481 type(qg_field), intent(in) :: self
1482 type(unstructured_grid), intent(inout) :: ug
1483 integer, intent(in) :: colocated
1484 
1485 integer :: igrid,imga,jx,jy,jl,jf,joff
1486 
1487 ! Copy colocated
1488 ug%colocated = colocated
1489 
1490 ! Define size
1491 call ug_size(self, ug)
1492 
1493 ! Allocate unstructured grid field
1495 
1496 ! Copy field
1497 if (ug%colocated==1) then
1498  ! Colocated
1499  imga = 0
1500  do jy=1,self%geom%ny
1501  do jx=1,self%geom%nx
1502  imga = imga+1
1503  do jf=1,self%nf
1504  joff = (jf-1)*self%nl
1505  do jl=1,self%nl
1506  ug%grid(1)%fld(imga,jl,jf,1) = self%gfld3d(jx,jy,joff+jl)
1507  enddo
1508  enddo
1509  enddo
1510  enddo
1511 else
1512  ! Not colocated
1513  do igrid=1,ug%ngrid
1514  imga = 0
1515  do jy=1,self%geom%ny
1516  do jx=1,self%geom%nx
1517  imga = imga+1
1518  do jf=1,self%nf
1519  joff = (jf-1)*self%nl
1520  do jl=1,self%nl
1521  ug%grid(igrid)%fld(imga,jl,jf,1) = self%gfld3d(jx,jy,joff+jl)
1522  enddo
1523  enddo
1524  enddo
1525  enddo
1526  enddo
1527 endif
1528 
1529 end subroutine field_to_ug
1530 
1531 ! ------------------------------------------------------------------------------
1532 
1533 subroutine field_from_ug(self, ug)
1535 implicit none
1536 type(qg_field), intent(inout) :: self
1537 type(unstructured_grid), intent(in) :: ug
1538 
1539 integer :: igrid,imga,jx,jy,jl,jf,joff
1540 
1541 ! Copy field
1542 if (ug%colocated==1) then
1543  ! Colocated (adjoint)
1544  imga = 0
1545  do jy=1,self%geom%ny
1546  do jx=1,self%geom%nx
1547  imga = imga+1
1548  do jf=1,self%nf
1549  joff = (jf-1)*self%nl
1550  do jl=1,self%nl
1551  self%gfld3d(jx,jy,joff+jl) = ug%grid(1)%fld(imga,jl,jf,1)
1552  enddo
1553  enddo
1554  enddo
1555  enddo
1556 else
1557  ! Not colocated
1558  do igrid=1,ug%ngrid
1559  imga = 0
1560  do jy=1,self%geom%ny
1561  do jx=1,self%geom%nx
1562  imga = imga+1
1563  do jf=1,self%nf
1564  joff = (jf-1)*self%nl
1565  do jl=1,self%nl
1566  self%gfld3d(jx,jy,joff+jl) = ug%grid(igrid)%fld(imga,jl,jf,1)
1567  enddo
1568  enddo
1569  enddo
1570  enddo
1571  enddo
1572 end if
1573 
1574 end subroutine field_from_ug
1575 
1576 ! ------------------------------------------------------------------------------
1577 
1578 function genfilename (c_conf,length,vdate)
1579 use iso_c_binding
1580 use datetime_mod
1581 use duration_mod
1582 type(c_ptr), intent(in) :: c_conf !< Configuration
1583 integer, intent(in) :: length
1584 character(len=length) :: genfilename
1585 type(datetime), intent(in) :: vdate
1586 
1587 character(len=length) :: fdbdir, expver, typ, validitydate, referencedate, sstep, &
1588  & prefix, mmb
1589 type(datetime) :: rdate
1590 type(duration) :: step
1591 integer lenfn
1592 
1593 ! here we should query the length and then allocate "string".
1594 ! But Fortran 90 does not allow variable-length allocatable strings.
1595 ! config_get_string checks the string length and aborts if too short.
1596 fdbdir = config_get_string(c_conf,len(fdbdir),"datadir")
1597 expver = config_get_string(c_conf,len(expver),"exp")
1598 typ = config_get_string(c_conf,len(typ) ,"type")
1599 
1600 if (typ=="ens") then
1601  mmb = config_get_string(c_conf, len(mmb), "member")
1602  lenfn = len_trim(fdbdir) + 1 + len_trim(expver) + 1 + len_trim(typ) + 1 + len_trim(mmb)
1603  prefix = trim(fdbdir) // "/" // trim(expver) // "." // trim(typ) // "." // trim(mmb)
1604 else
1605  lenfn = len_trim(fdbdir) + 1 + len_trim(expver) + 1 + len_trim(typ)
1606  prefix = trim(fdbdir) // "/" // trim(expver) // "." // trim(typ)
1607 endif
1608 
1609 if (typ=="fc" .or. typ=="ens") then
1610  referencedate = config_get_string(c_conf,len(referencedate),"date")
1611  call datetime_to_string(vdate, validitydate)
1612  call datetime_create(trim(referencedate), rdate)
1613  call datetime_diff(vdate, rdate, step)
1614  call duration_to_string(step, sstep)
1615  lenfn = lenfn + 1 + len_trim(referencedate) + 1 + len_trim(sstep)
1616  genfilename = trim(prefix) // "." // trim(referencedate) // "." // trim(sstep)
1617 endif
1618 
1619 if (typ=="an") then
1620  call datetime_to_string(vdate, validitydate)
1621  lenfn = lenfn + 1 + len_trim(validitydate)
1622  genfilename = trim(prefix) // "." // trim(validitydate)
1623 endif
1624 
1625 if (lenfn>length) &
1626  & call abor1_ftn("qg_fields:genfilename: filename too long")
1627 
1628 end function genfilename
1629 
1630 ! ------------------------------------------------------------------------------
1631 
1632 function common_vars(x1, x2)
1634 implicit none
1635 type(qg_field), intent(in) :: x1, x2
1636 integer :: common_vars
1637 integer :: jf
1638 
1639 ! We assume here that one set of fields is a subset of the other,
1640 ! that fields are always in the same order starting with x,
1641 ! and that the common fields are the first ones.
1642 
1643 common_vars = min(x1%nf, x2%nf)
1644 do jf = 1, common_vars
1645  if (x1%fldnames(jf)/=x2%fldnames(jf)) &
1646  & call abor1_ftn("common_vars: fields do not match")
1647 enddo
1648 if (x1%nl /= x2%nl) call abor1_ftn("common_vars: error number of levels")
1649 common_vars = x1%nl * common_vars
1650 
1651 end function common_vars
1652 
1653 ! ------------------------------------------------------------------------------
1654 
1655 subroutine check_resolution(x1, x2)
1657 implicit none
1658 type(qg_field), intent(in) :: x1, x2
1659 
1660 if (x1%geom%nx /= x2%geom%nx .or. x1%geom%ny /= x2%geom%ny .or. x1%nl /= x2%nl) then
1661  call abor1_ftn ("qg_fields: resolution error")
1662 endif
1663 call check(x1)
1664 call check(x2)
1665 
1666 end subroutine check_resolution
1667 
1668 ! ------------------------------------------------------------------------------
1669 
1670 subroutine check(self)
1671 implicit none
1672 type(qg_field), intent(in) :: self
1673 logical :: bad
1674 
1675 bad = .not.associated(self%gfld3d)
1676 
1677 bad = bad .or. (size(self%gfld3d, 1) /= self%geom%nx)
1678 bad = bad .or. (size(self%gfld3d, 2) /= self%geom%ny)
1679 bad = bad .or. (size(self%gfld3d, 3) /= self%nl*self%nf)
1680 
1681 bad = bad .or. .not.associated(self%x)
1682 
1683 if (self%nf>1) then
1684  bad = bad .or. .not.associated(self%q)
1685  bad = bad .or. .not.associated(self%u)
1686  bad = bad .or. .not.associated(self%v)
1687 else
1688  bad = bad .or. associated(self%q)
1689  bad = bad .or. associated(self%u)
1690  bad = bad .or. associated(self%v)
1691 endif
1692 
1693 !allocate(self%fldnames(self%nf))
1694 
1695 if (self%lbc) then
1696  bad = bad .or. .not.associated(self%xbound)
1697  bad = bad .or. (size(self%xbound) /= 4)
1698 
1699  bad = bad .or. .not.associated(self%qbound)
1700  bad = bad .or. (size(self%qbound, 1) /= self%geom%nx)
1701  bad = bad .or. (size(self%qbound, 2) /= 4)
1702 else
1703  bad = bad .or. associated(self%xbound)
1704  bad = bad .or. associated(self%qbound)
1705 endif
1706 
1707 if (bad) then
1708  write(0,*)'nx, ny, nf, nl, lbc = ',self%geom%nx,self%geom%ny,self%nf,self%nl,self%lbc
1709  if (associated(self%gfld3d)) write(0,*)'shape(gfld3d) = ',shape(self%gfld3d)
1710  if (associated(self%xbound)) write(0,*)'shape(xbound) = ',shape(self%xbound)
1711  if (associated(self%qbound)) write(0,*)'shape(qbound) = ',shape(self%qbound)
1712  call abor1_ftn ("qg_fields: field not consistent")
1713 endif
1714 
1715 end subroutine check
1716 
1717 ! ------------------------------------------------------------------------------
1718 
1719 subroutine ncerr(info)
1721 implicit none
1722 
1723 ! Passed variables
1724 integer,intent(in) :: info !< Info index
1725 
1726 ! Check status
1727 if (info/=nf90_noerr) then
1728  write(*,*) trim(nf90_strerror(info))
1729  stop
1730 end if
1731 
1732 end subroutine ncerr
1733 
1734 end module qg_fields
real(kind=kind_real), parameter domain_meridional
meridional model domain (m)
Fortran derived type to represent QG model variables.
Definition: qg_vars_mod.F90:23
subroutine, public allocate_unstructured_grid_coord(self)
Fortran generic for generating random 1d, 2d and 3d arrays.
subroutine, public self_mul(self, zz)
Definition: qg_fields.F90:315
subroutine calc_streamfunction(kx, ky, x, u, v, dx, dy)
Calculate Streamfunction from u and v.
Definition: qg_fields.F90:895
subroutine, public axpy(self, zz, rhs)
Definition: qg_fields.F90:333
type(registry_t), public qg_field_registry
Linked list interface - defines registry_t type.
Definition: qg_fields.F90:65
subroutine, public read_file(fld, c_conf, vdate)
Definition: qg_fields.F90:524
real(kind=kind_real), parameter f0
Coriolis parameter at southern boundary.
character(len=length) function genfilename(c_conf, length, vdate)
Definition: qg_fields.F90:1579
Fortran derived type to hold geometry data for the QG model.
Definition: qg_geom_mod.F90:26
subroutine lin_weights(kk, delta1, delta2, k1, k2, w1, w2)
Definition: qg_fields.F90:1345
subroutine check(action, status)
real(kind=kind_real), parameter g
gravity (m^2 s^{-2})
subroutine test1_advection_deformation(lon, lat, p, z, zcoords, u, v, w, t, phis, ps, rho, q, q1, q2, q3, q4)
subroutine, public copy(self, rhs)
Definition: qg_fields.F90:225
subroutine, public create(self, geom, vars)
Linked list implementation.
Definition: qg_fields.F90:76
subroutine deriv_1d(df, f, n, delta, periodic)
Finite Difference Derivative.
Definition: qg_fields.F90:945
subroutine, public random(self)
Definition: qg_fields.F90:208
subroutine, public self_schur(self, rhs)
Definition: qg_fields.F90:273
subroutine, public self_add(self, rhs)
Definition: qg_fields.F90:252
Constants for the QG model.
subroutine, public add_incr(self, rhs)
Definition: qg_fields.F90:392
subroutine ug_size(self, ug)
Definition: qg_fields.F90:1368
subroutine, public interp_tl(fld, locs, vars, gom)
Definition: qg_fields.F90:1166
subroutine solve_helmholz(x, b, c, nx, ny, deltax, deltay)
Solve a Helmholz equation.
subroutine check_resolution(x1, x2)
Definition: qg_fields.F90:1656
subroutine calc_pv(kx, ky, pv, x, x_north, x_south, f1, f2, deltax, deltay, bet, rs, lbc)
Calculate potential vorticity from streamfunction.
Definition: calc_pv.f90:21
Fortran module handling geometry for the QG model.
Definition: qg_geom_mod.F90:11
subroutine ncerr(info)
Definition: qg_fields.F90:1720
subroutine, public diff_incr(lhs, x1, x2)
Definition: qg_fields.F90:424
subroutine, public dirac(self, c_conf)
Definition: qg_fields.F90:167
subroutine, public ug_coord(self, ug, colocated)
Definition: qg_fields.F90:1422
subroutine, public field_to_ug(self, ug, colocated)
Definition: qg_fields.F90:1479
Fortran module handling observation locations.
Definition: qg_locs_mod.F90:11
subroutine invent_state(flds, config)
Invent an initial state for the QG model.
subroutine, public write_file(fld, c_conf, vdate)
Definition: qg_fields.F90:994
subroutine, public field_from_ug(self, ug)
Definition: qg_fields.F90:1534
subroutine, public interp_ad(fld, locs, vars, gom)
Definition: qg_fields.F90:1253
subroutine, public allocate_unstructured_grid_field(self)
subroutine, public dot_prod(fld1, fld2, zprod)
Definition: qg_fields.F90:355
Fortran derived type to hold QG fields.
Definition: qg_fields.F90:38
Fortran module to handle variables for the QG model.
Definition: qg_vars_mod.F90:11
Handle fields for the QG model.
Definition: qg_fields.F90:11
Fortran module for generating random vectors.
subroutine test1_advection_hadley(lon, lat, p, z, zcoords, u, v, w, t, phis, ps, rho, q, q1)
subroutine, public analytic_init(fld, geom, config, vdate)
Analytic Initialization for the QG model.
Definition: qg_fields.F90:707
subroutine, public zeros(self)
Definition: qg_fields.F90:151
subroutine, public fldrms(fld, prms)
Definition: qg_fields.F90:1126
subroutine, public self_sub(self, rhs)
Definition: qg_fields.F90:294
real(kind=kind_real), parameter domain_zonal
model domain (m) in zonal direction
real(kind=kind_real), parameter dlogtheta
difference in log(pot. T) across boundary
integer function common_vars(x1, x2)
Definition: qg_fields.F90:1633
subroutine, public change_resol(fld, rhs)
Definition: qg_fields.F90:463
Fortran module handling interpolated (to obs locations) model variables.
Definition: qg_goms_mod.F90:11
logical netcdfio
Definition: qg_fields.F90:57
integer, parameter, public kind_real
#define min(a, b)
Definition: mosaic_util.h:32
Fortran module for handling generic unstructured grid.
subroutine, public gpnorm(fld, nf, pstat)
Definition: qg_fields.F90:1089
real(kind=kind_real), parameter scale_length
horizontal length scale (m)
real(fp), parameter, public pi
subroutine, public delete(self)
Definition: qg_fields.F90:136