FV3-JEDI
fv3jedi_linvarcha_nmcbal_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2018 UCAR
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 
7 
8 use fckit_configuration_module, only: fckit_configuration
9 
10 use netcdf
12 
16 use iso_c_binding
17 use fckit_configuration_module, only: fckit_configuration
18 use fckit_mpi_module, only: fckit_mpi_comm
21 use mpp_domains_mod, only: center
22 
26 use wind_vt_mod
27 
28 use type_gaugrid, only: gaussian_grid
31 
32 implicit none
33 private
34 
35 integer,parameter :: r_single = 4
36 
38 public :: create
39 public :: delete
40 public :: multiply
41 public :: multiplyadjoint
42 public :: multiplyinverse
43 public :: multiplyinverseadjoint
44 
45 !> Fortran derived type to hold configuration data for the B mat variable change
47 
48  integer :: npe ! size of PEs
49  integer :: mype ! my rank
50 
51  !
52  ! Cubed-sphere grid
53  !
54  integer :: isc,iec,jsc,jec,npz
55  integer :: ngrid_cs ! data size for grid interpolation
56  type(fv3jedi_geom) :: geom_cs
57  ! increments
58  real(kind=kind_real), allocatable :: fld(:,:,:,:)
59 
60  ! trajectores for varchange
61  real(kind=kind_real), allocatable :: ttraj(:,:,:) ! tempature
62  real(kind=kind_real), allocatable :: tvtraj(:,:,:) ! virtual tempature
63  real(kind=kind_real), allocatable :: qtraj(:,:,:) ! specific humidity
64  real(kind=kind_real), allocatable :: qsattraj(:,:,:) ! saturation specific hum.
65 
66  !
67  ! Gaussian grid
68  !
69  type(gaussian_grid) :: glb ! global Gaussian grid
70  type(gaussian_grid) :: gg ! local Gaussian grd
71  integer :: nx,ny,nz,nv ! gobal grid size
72  integer :: x2,y2,z2 ! local grid size with halo
73  integer :: hx,hy ! halo size
74  integer :: layout(2) ! domain layout
75  integer,allocatable :: istrx(:),jstry(:) ! start index at each subdomain
76  integer :: ngrid_ggh, ngrid_gg ! data size for grid interpolation (with and without halo)
77  ! regression coeffs for GSI unbalanced variables
78  character(len=256) :: path_to_nmcbalance_coeffs ! path to netcdf file
79  integer :: read_latlon_from_nc ! 1: read rlats/rlons of
80  ! global gaugrid from
81  ! netcdf
82  real(kind=kind_real), allocatable :: agvz(:,:,:) ! coeffs. for psi and t
83  real(kind=kind_real), allocatable :: wgvz(:,:) ! coeffs. for psi and ps
84  real(kind=kind_real), allocatable :: bvz(:,:) ! coeffs. for psi and chi
85  ! data pointer
86  real(kind=kind_real), pointer :: psi(:,:,:) => null() ! stream function
87  real(kind=kind_real), pointer :: chi(:,:,:) => null() ! velocity potential
88  real(kind=kind_real), pointer :: tv(:,:,:) => null() ! virtual tempature
89  real(kind=kind_real), pointer :: ps(:,:) => null() ! surface pressure
90 
91  !
92  ! bump interpolation
93  !
94  type(fv3jedi_bump_interp) :: c2g ! bump_interpolation from cubed-sphere to Gaussian grid
95  type(fv3jedi_bump_interp) :: g2c ! bump interpolation from Gaussian to cubed-sphere grid
96 
98 
99 ! ------------------------------------------------------------------------------
100 
101 contains
102 
103 ! ------------------------------------------------------------------------------
104 
105 subroutine create(self, geom, bg, fg, conf)
106 
107 implicit none
108 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
109 type(fv3jedi_geom), target, intent(in) :: geom
110 type(fv3jedi_state), target, intent(in) :: bg
111 type(fv3jedi_state), target, intent(in) :: fg
112 type(fckit_configuration), intent(in) :: conf
113 
114 real(kind=kind_real), pointer :: t(:,:,:)
115 real(kind=kind_real), pointer :: q(:,:,:)
116 real(kind=kind_real), pointer :: delp(:,:,:)
117 
118 integer :: hx,hy,layoutx,layouty,read_latlon_from_nc
119 character(len=:),allocatable :: str
120 
121 ! Cubed-sphere grid geometry
122 call self%geom_cs%clone(geom,geom%fields)
123 self%npe = geom%f_comm%size()
124 self%mype = geom%f_comm%rank()
125 
126 ! 1. Get trajectores
127 !> Pointers to the background state
128 call bg%get_field('t' , t)
129 call bg%get_field('sphum' , q)
130 call bg%get_field('delp', delp)
131 
132 !> Virtual temperature trajectory
133 allocate(self%tvtraj (geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
134 call t_to_tv(geom,t,q,self%tvtraj)
135 
136 !> Temperature trajectory
137 allocate(self%ttraj (geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
138 self%ttraj = t
139 
140 !> Specific humidity trajecotory
141 allocate(self%qtraj (geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
142 self%qtraj = q
143 
144 !> Compute saturation specific humidity for q to RH transform
145 allocate(self%qsattraj(geom%isc:geom%iec,geom%jsc:geom%jec,1:geom%npz))
146 
147 !> Compute saturation specific humidity
148 call get_qsat(geom,delp,t,q,self%qsattraj)
149 
150 !> temporary fields for grid interpolation
151 self%isc = geom%isc; self%iec = geom%iec
152 self%jsc = geom%jsc; self%jec = geom%jec
153 self%npz = geom%npz
154 ! fields
155 allocate(self%fld(self%isc:self%iec,self%jsc:self%jec,self%npz,4))
156 self%fld = 0.0_kind_real
157 
158 ! 2. Read balance operator grid from NetCDF
159 if (conf%has("path_to_nmcbalance_coeffs")) then
160  call conf%get_or_die("path_to_nmcbalance_coeffs",str)
161  self%path_to_nmcbalance_coeffs = str
162  deallocate(str)
163 else
164  call abor1_ftn("fv3jedi_linvarcha_nmcbal_mod.create:&
165 & path_to_nmcbalance_coeffs must be set in configuration file")
166 end if
167 call read_nmcbalance_grid(self)
168 
169 ! 3. Create Gaussian grid
170 self%hx = 1; self%hy = 1 ! default halo size
171 if(conf%has("hx")) then
172  call conf%get_or_die("hx",hx); self%hx = hx
173 end if
174 if(conf%has("hy")) then
175  call conf%get_or_die("hy",hy); self%hy = hy
176 end if
177 
178 allocate(self%istrx(self%npe))
179 allocate(self%jstry(self%npe))
180 
181 ! set subdomain
182 
183 if(conf%has("layoutx").and.conf%has("layouty")) then
184  call conf%get_or_die("layoutx",layoutx)
185  call conf%get_or_die("layouty",layouty)
186  if(layoutx*layouty/=self%npe) then
187  call abor1_ftn("fv3jedi_linvarcha_nmcbal_mod.create:&
188 & invalid layout values")
189  end if
190  self%layout(1) = layoutx
191  self%layout(2) = layouty
192 else
193  if(self%npe==24)then
194  self%layout(1)=6
195  self%layout(2)=4
196  else if(self%npe==18)then
197  self%layout(1)=6
198  self%layout(2)=3
199  else if(self%npe==12)then
200  self%layout(1)=4
201  self%layout(2)=3
202  else if(self%npe==6)then
203  self%layout(1)=3
204  self%layout(2)=2
205  else
206  self%layout(1)=self%npe
207  self%layout(2)=1
208  end if
209 end if
210 call deter_subdomain(self)
211 
212 ! set Gaussian grid parameters
213 self%nv = 4 ! psi,chi,tv,ps
214 self%z2 = self%nz
215 !self%z2 = (nz*3+1)/self%npe
216 !if(mod(nz*3+1,self%npe)/=0) self%z2 = self%z2 + 1
217 self%glb%nlat = self%ny; self%gg%nlat = self%y2
218 self%glb%nlon = self%nx; self%gg%nlon = self%x2
219 self%glb%nlev = self%nz; self%gg%nlev = self%z2
220 self%glb%nvar = self%nv; self%gg%nvar = self%nv
221 
222 ! allocate and initialize
223 call self%glb%create(); call self%gg%create()
224 
225 ! set Gaussian field pointer
226 call self%gg%fld3d_pointer(1,'psi',self%psi)
227 call self%gg%fld3d_pointer(2,'chi',self%chi)
228 call self%gg%fld3d_pointer(3,'tv' ,self%tv)
229 call self%gg%fld2d_pointer(4,'ps' ,self%ps)
230 
231 ! calculate and set Gaussian lat-lon
232 self%read_latlon_from_nc = 0
233 if(conf%has("read_latlon_from_nc")) then
234  call conf%get_or_die("read_latlon_from_nc",read_latlon_from_nc)
235  self%read_latlon_from_nc = read_latlon_from_nc
236 end if
237 if(self%read_latlon_from_nc==1) then
238  call read_nmcbalance_latlon(self)
239 else
240  call self%glb%calc_glb_latlon()
241 end if
242 call set_gaugrid_latlon(self)
243 
244 ! 4. Create interplation weights (bump)
245 call bump_init_gaugrid(self,geom)
246 
247 ! 5. Read balance coeffs from fixed file
248 allocate(self%agvz(self%gg%nlat,self%gg%nlev,self%gg%nlev))
249 allocate(self%wgvz(self%gg%nlat,self%gg%nlev))
250 allocate(self%bvz (self%gg%nlat,self%gg%nlev))
251 call read_nmcbalance_coeffs(self)
252 
253 end subroutine create
254 
255 ! ------------------------------------------------------------------------------
256 
257 subroutine delete(self)
258 
259 implicit none
260 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
261 
262 ! Deallacote everthing
263 if (allocated(self%tvtraj)) deallocate(self%tvtraj)
264 if (allocated(self%ttraj)) deallocate(self%ttraj)
265 if (allocated(self%qtraj)) deallocate(self%qtraj)
266 if (allocated(self%qsattraj)) deallocate(self%qsattraj)
267 
268 if (allocated(self%istrx)) deallocate(self%istrx)
269 if (allocated(self%jstry)) deallocate(self%jstry)
270 if (allocated(self%agvz)) deallocate(self%agvz)
271 if (allocated(self%wgvz)) deallocate(self%wgvz)
272 if (allocated(self%bvz)) deallocate(self%bvz)
273 
274 if (allocated(self%fld)) deallocate(self%fld)
275 
276 ! Nullify pointers
277 if (associated(self%psi)) nullify(self%psi)
278 if (associated(self%chi)) nullify(self%chi)
279 if (associated(self%tv)) nullify(self%tv)
280 if (associated(self%ps)) nullify(self%ps)
281 
282 call self%glb%delete()
283 call self%gg%delete()
284 
285 call self%c2g%delete()
286 call self%g2c%delete()
287 
288 end subroutine delete
289 
290 ! ------------------------------------------------------------------------------
291 
292 subroutine multiply(self,geom,xuba,xbal)
293 
294 implicit none
295 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
296 type(fv3jedi_geom), intent(inout) :: geom
297 type(fv3jedi_increment), intent(in) :: xuba
298 type(fv3jedi_increment), intent(inout) :: xbal
299 
300 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_psi
301 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_chi
302 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_tv
303 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_rh
304 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_ps
305 
306 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ua
307 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_va
308 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_t
309 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_q
310 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ps
311 
312 real(kind_real), allocatable :: psi_d(:,:,:), chi_d(:,:,:) ! psi/chi on D-grid
313 
314 ! Copy fields that are the same in both
315 ! -------------------------------------
316 call copy_subset(xuba%fields,xbal%fields)
317 
318 !Tangent linear of control to analysis variables
319 call xuba%get_field('psi', xuba_psi)
320 call xuba%get_field('chi', xuba_chi)
321 call xuba%get_field('tv' , xuba_tv)
322 call xuba%get_field('rh' , xuba_rh)
323 call xuba%get_field('ps' , xuba_ps)
324 call xbal%get_field('ua' , xbal_ua)
325 call xbal%get_field('va' , xbal_va)
326 call xbal%get_field('t' , xbal_t)
327 call xbal%get_field('sphum' , xbal_q)
328 call xbal%get_field('ps' , xbal_ps)
329 
330 ! Apply Balance operator to psi,chi,tv(,ps)
331 
332 ! input cubed-sphere fields
333 self%fld(:,:,:,1) = xuba_psi
334 self%fld(:,:,:,2) = xuba_chi
335 self%fld(:,:,:,3) = xuba_tv
336 self%fld(:,:,1:1,4) = xuba_ps
337 
338 ! 1. Intep to Gaussian grid (using bump)
339 call field_interp_to_gaugrid(self)
340 
341 ! 2. Apply balance operator
342 call balance(self)
343 
344 ! 3. Intep back to cubed-sphere grid (using bump)
345 call field_interp_from_gaugrid(self)
346 
347 ! 4. Linear variable changes (Control to Analysis)
348 !psi/chi -> ua/va
349 allocate(psi_d(geom%isd:geom%ied,geom%jsd:geom%jed,1:geom%npz))
350 allocate(chi_d(geom%isd:geom%ied,geom%jsd:geom%jed,1:geom%npz))
351 psi_d = 0.0_kind_real; chi_d = 0.0_kind_real
352 psi_d(geom%isc:geom%iec,geom%jsc:geom%jec,:) = self%fld(:,:,:,1)
353 chi_d(geom%isc:geom%iec,geom%jsc:geom%jec,:) = self%fld(:,:,:,2)
354 call psichi_to_uava(geom,psi_d,chi_d,xbal_ua,xbal_va)
355 deallocate(psi_d,chi_d)
356 
357 !rh -> q
358 call rh_to_q_tl(geom,self%qsattraj,xuba_rh,xbal_q)
359 
360 !Tv -> T
361 call tv_to_t_tl(geom,self%tvtraj,self%fld(:,:,:,3),self%qtraj,xbal_q,xbal_t)
362 
363 !Ps
364 xbal_ps = self%fld(:,:,1:1,4)
365 
366 ! Copy calendar infomation
367 xbal%calendar_type = xuba%calendar_type
368 xbal%date_init = xuba%date_init
369 
370 end subroutine multiply
371 
372 ! ------------------------------------------------------------------------------
373 
374 subroutine multiplyadjoint(self,geom,xbal,xuba)
375 
376 implicit none
377 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
378 type(fv3jedi_geom), intent(inout) :: geom
379 type(fv3jedi_increment), intent(inout) :: xbal
380 type(fv3jedi_increment), intent(inout) :: xuba
381 
382 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ua
383 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_va
384 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_t
385 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_q
386 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ps
387 
388 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_psi
389 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_chi
390 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_tv
391 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_rh
392 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_ps
393 
394 real(kind_real), allocatable :: psi_d(:,:,:), chi_d(:,:,:) ! psi/chi on D-grid
395 real(kind_real), allocatable :: ps_not_copied(:,:,:)
396 
397 ! Copy fields that are the same in both
398 ! -------------------------------------
399 allocate(ps_not_copied(geom%isc:geom%iec,geom%jsc:geom%jec,1))
400 call xuba%get_field('ps', ps_not_copied) ! temporary copy
401 call copy_subset(xbal%fields,xuba%fields)
402 
403 !Tangent linear of control to analysis variables
404 call xbal%get_field('ua' , xbal_ua)
405 call xbal%get_field('va' , xbal_va)
406 call xbal%get_field('t' , xbal_t)
407 call xbal%get_field('sphum' , xbal_q)
408 call xbal%get_field('ps' , xbal_ps)
409 call xuba%get_field('psi', xuba_psi)
410 call xuba%get_field('chi', xuba_chi)
411 call xuba%get_field('tv' , xuba_tv)
412 call xuba%get_field('rh' , xuba_rh)
413 call xuba%get_field('ps' , xuba_ps)
414 
415 xuba_ps(:,:,1) = ps_not_copied(:,:,1)
416 deallocate(ps_not_copied)
417 
418 self%fld = 0.0_kind_real
419 
420 ! 1. Adjoint of linear variable changes (Control to Analysis)
421 !Ps
422 self%fld(:,:,1:1,4) = xbal_ps; xbal_ps = 0.0_kind_real
423 
424 !Tv -> T
425 call tv_to_t_ad(geom,self%tvtraj,self%fld(:,:,:,3),self%qtraj,xbal_q,xbal_t)
426 
427 !rh -> q
428 call rh_to_q_ad(geom,self%qsattraj,xuba_rh,xbal_q)
429 
430 !psi/chi -> ua/va
431 allocate(psi_d(geom%isd:geom%ied,geom%jsd:geom%jed,1:geom%npz))
432 allocate(chi_d(geom%isd:geom%ied,geom%jsd:geom%jed,1:geom%npz))
433 psi_d = 0.0_kind_real; chi_d = 0.0_kind_real
434 call psichi_to_uava_adm(geom,psi_d,chi_d,xbal_ua,xbal_va)
435 self%fld(:,:,:,1) = psi_d(geom%isc:geom%iec,geom%jsc:geom%jec,:)
436 self%fld(:,:,:,2) = chi_d(geom%isc:geom%iec,geom%jsc:geom%jec,:)
437 deallocate(psi_d,chi_d)
438 
439 ! 2. Adjoint of intep. back to cubed-sphere grid
441 
442 ! 3. Adjoint of applying balance operator
443 call tbalance(self)
444 
445 ! 4. Adjoint of intep. to Gaussian grid
447 
448 xuba_ps = xuba_ps + self%fld(:,:,1:1,4)
449 xuba_tv = xuba_tv + self%fld(:,:,:,3)
450 xuba_psi = xuba_psi + self%fld(:,:,:,1)
451 xuba_chi = xuba_chi + self%fld(:,:,:,2)
452 self%fld = 0.0_kind_real
453 
454 ! Copy calendar infomation
455 xuba%calendar_type = xbal%calendar_type
456 xuba%date_init = xbal%date_init
457 
458 end subroutine multiplyadjoint
459 
460 ! ------------------------------------------------------------------------------
461 
462 subroutine multiplyinverse(self,geom,xbal,xuba)
463 
464 implicit none
465 type(fv3jedi_linvarcha_nmcbal), intent(in) :: self
466 type(fv3jedi_geom), intent(inout) :: geom
467 type(fv3jedi_increment), intent(in) :: xbal
468 type(fv3jedi_increment), intent(inout) :: xuba
469 
470 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ua
471 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_va
472 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_t
473 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_q
474 
475 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_psi
476 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_chi
477 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_tv
478 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_rh
479 
480 
481 ! Copy fields that are the same in both
482 ! -------------------------------------
483 call copy_subset(xbal%fields,xuba%fields)
484 
485 !Tangent linear of control to analysis variables
486 call xbal%get_field('ua' , xbal_ua)
487 call xbal%get_field('va' , xbal_va)
488 call xbal%get_field('t' , xbal_t)
489 call xbal%get_field('sphum' , xbal_q)
490 call xuba%get_field('psi', xuba_psi)
491 call xuba%get_field('chi', xuba_chi)
492 call xuba%get_field('tv' , xuba_tv)
493 call xuba%get_field('rh' , xuba_rh)
494 
495 xuba_psi = xbal_ua
496 xuba_chi = xbal_va
497 xuba_tv = xbal_t
498 xuba_rh = xbal_q
499 
500 ! Copy calendar infomation
501 xuba%calendar_type = xbal%calendar_type
502 xuba%date_init = xbal%date_init
503 
504 end subroutine multiplyinverse
505 
506 ! ------------------------------------------------------------------------------
507 
508 subroutine multiplyinverseadjoint(self,geom,xuba,xbal)
509 
510 implicit none
511 type(fv3jedi_linvarcha_nmcbal), intent(in) :: self
512 type(fv3jedi_geom), intent(inout) :: geom
513 type(fv3jedi_increment), intent(in) :: xuba
514 type(fv3jedi_increment), intent(inout) :: xbal
515 
516 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_psi
517 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_chi
518 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_tv
519 real(kind=kind_real), pointer, dimension(:,:,:) :: xuba_rh
520 
521 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_ua
522 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_va
523 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_t
524 real(kind=kind_real), pointer, dimension(:,:,:) :: xbal_q
525 
526 ! Copy fields that are the same in both
527 ! -------------------------------------
528 call copy_subset(xuba%fields,xbal%fields)
529 
530 !Tangent linear of control to analysis variables
531 call xuba%get_field('psi', xuba_psi)
532 call xuba%get_field('chi', xuba_chi)
533 call xuba%get_field('tv' , xuba_tv)
534 call xuba%get_field('rh' , xuba_rh)
535 call xbal%get_field('ua' , xbal_ua)
536 call xbal%get_field('va' , xbal_va)
537 call xbal%get_field('t' , xbal_t)
538 call xbal%get_field('sphum' , xbal_q)
539 
540 xbal_ua = xuba_psi
541 xbal_va = xuba_chi
542 xbal_t = xuba_tv
543 xbal_q = xuba_rh
544 
545 ! Copy calendar infomation
546 xbal%calendar_type = xuba%calendar_type
547 xbal%date_init = xuba%date_init
548 
549 end subroutine multiplyinverseadjoint
550 
551 ! ------------------------------------------------------------------------------
552 ! Determine subdomain settings
553 ! This subroutine was migrated from gsi/general_sub2grid_mod.F90
554 subroutine deter_subdomain(self)
555 
556 implicit none
557 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
558 
559 if(self%layout(2)==1)then
560  call deter_subdomain_nolayout(self)
561 else
562  call deter_subdomain_withlayout(self)
563 end if
564 
565 end subroutine deter_subdomain
566 
567 ! -------------------------------------
568 
570 
571 implicit none
572 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
573 
574 integer:: nxpe,nype
575 integer,allocatable:: imxy(:), jmxy(:)
576 integer:: i,j,k,istart0, jstart0
577 integer:: im,jm,mm1
578 
579 integer,allocatable,dimension(:) :: jlon1,ilat1
580 
581 nxpe=self%layout(1)
582 nype=self%layout(2)
583 allocate(imxy(nxpe))
584 allocate(jmxy(nype))
585 
586 ! start
587 
588 im=self%nx
589 jm=self%ny
590 call get_local_dims_ ( im,imxy,nxpe )
591 call get_local_dims_ ( jm,jmxy,nype )
592 
593 allocate(jlon1(self%npe))
594 allocate(ilat1(self%npe))
595 
596 ! compute subdomain boundaries (axis indices)
597 
598 ! compute local subdomain (offset and sizes)
599 
600 k=0
601 jstart0 = 1
602 self%istrx=1
603 self%jstry=1
604 do j=1,nype
605  istart0 = 1
606  if (j>1) then
607  jstart0 = jstart0 + jmxy(j-1)
608  end if
609  do i=1,nxpe
610  k = k + 1
611  ilat1(k) = jmxy(j)
612  self%jstry(k) = jstart0
613  jlon1(k) = imxy(i)
614  if (i>1) then
615  istart0 = istart0 + imxy(i-1)
616  end if
617  self%istrx(k) = istart0
618  end do
619 end do
620 
621 ! Set number of latitude and longitude for given subdomain
622 mm1=self%mype+1
623 self%y2=ilat1(mm1)+self%hy*2
624 self%x2=jlon1(mm1)+self%hx*2
625 deallocate(ilat1,jlon1)
626 deallocate(imxy,jmxy)
627 
628 end subroutine deter_subdomain_withlayout
629 
630 ! -------------------------------------
631 
632 subroutine deter_subdomain_nolayout(self)
633 
634 implicit none
635 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
636 
637 integer :: npts,nrnc,iinum,iileft,jrows,jleft,k,i,jjnum
638 integer :: j,mm1,iicnt,ipts,jjleft
639 integer,allocatable,dimension(:) :: jlon1,ilat1
640 integer,allocatable,dimension(:) :: iiend,jjend,iistart
641 real(kind_real) :: anperpe
642 
643 ! Compute number of points on full grid
644 ! and target number of point per mpi task (pe)
645 npts=self%nx*self%ny
646 if(self%npe<=0) then
647  call abor1_ftn("fv3jedi_linvarcha_nmcbal_mod.deter_subdomain_nolayout:&
648 & npe has invalid value")
649 end if
650 anperpe=float(npts)/float(self%npe)
651 
652 ! Start with square subdomains
653 nrnc=int(sqrt(anperpe))
654 iinum=self%nx/nrnc
655 if(iinum==0) iinum=1
656 iicnt=self%nx/iinum
657 iileft=self%nx-iicnt*iinum
658 jrows=self%npe/iinum
659 jleft=self%npe-jrows*iinum
660 
661 ! Adjust subdomain boundaries
662 k=0
663 self%istrx=1
664 self%jstry=1
665 allocate(iistart(self%npe+1))
666 allocate(iiend(self%npe+1))
667 allocate(jjend(self%npe+1))
668 allocate(jlon1(self%npe))
669 allocate(ilat1(self%npe))
670 iistart(1)=1
671 do i=1,iinum
672  ipts = iicnt
673  if(i <= iileft)ipts=ipts+1
674  iiend(i)=iistart(i)+ipts-1
675  iistart(i+1)=iiend(i)+1
676  jjnum=jrows
677  if(i <= jleft)jjnum=jrows+1
678  do j=1,jjnum
679  k=k+1
680  jlon1(k)=ipts
681  self%istrx(k)= iistart(i)
682  ilat1(k)=self%ny/jjnum
683  jjleft=self%ny-ilat1(k)*jjnum
684  if(j <= jjleft)ilat1(k)=ilat1(k)+1
685  if(j > 1)self%jstry(k)=jjend(j-1)+1
686  jjend(j)=self%jstry(k)+ilat1(k)-1
687  end do
688 end do
689 deallocate(iistart,iiend,jjend)
690 
691 ! Set number of latitude and longitude for given subdomain
692 mm1=self%mype+1
693 self%y2=ilat1(mm1)+self%hy*2
694 self%x2=jlon1(mm1)+self%hx*2
695 deallocate(ilat1,jlon1)
696 
697 end subroutine deter_subdomain_nolayout
698 
699 ! -------------------------------------
700 
701 subroutine get_local_dims_(dim_world,dim,ndes)
702 
703 implicit none
704 integer,intent(in ) :: dim_world, ndes
705 integer,intent(inout) :: dim(0:ndes-1)
706 integer :: n,im,rm
707 
708 im = dim_world/ndes
709 rm = dim_world-ndes*im
710 do n=0,ndes-1
711  dim(n) = im
712  if( n<=rm-1 ) dim(n) = im+1
713 end do
714 
715 end subroutine get_local_dims_
716 
717 ! ------------------------------------------------------------------------------
718 ! Set local Gausisan latitudes and longitudes
719 subroutine set_gaugrid_latlon(self)
720 
721 implicit none
722 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
723 integer :: i,j,ix,jy
724 
725 ! Latitudes
726 jy=self%jstry(self%mype+1)-self%hy
727 do j=1,self%gg%nlat
728  if(jy<=0) jy=1
729  if(jy>=self%glb%nlat+1) jy=self%glb%nlat
730  self%gg%rlats(j)=self%glb%rlats(jy)
731  jy = self%jstry(self%mype+1)-self%hy+j
732 end do
733 
734 ! Longitudes
735 ix=self%istrx(self%mype+1)-self%hx
736 do i=1,self%gg%nlon
737  if(ix<=0) ix=ix+self%glb%nlon
738  if(ix>self%glb%nlon) ix=ix-self%glb%nlon
739  self%gg%rlons(i) = self%glb%rlons(ix)
740  ix=self%istrx(self%mype+1)-self%hx+i
741 end do
742 
743 end subroutine set_gaugrid_latlon
744 
745 ! ------------------------------------------------------------------------------
746 ! Setup bump for grid interpolation
747 subroutine bump_init_gaugrid(self,geom)
748 
749 implicit none
750 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
751 type(fv3jedi_geom), target, intent(in) :: geom
752 
753 integer :: jx,jy,jnode
754 real(kind=kind_real), pointer :: real_ptr(:,:)
755 real(kind=kind_real), allocatable :: lon_cs(:) ! Cubed-sphere longitudes
756 real(kind=kind_real), allocatable :: lat_cs(:) ! Cubed-sphere latitudes
757 real(kind=kind_real), allocatable :: lon_ggh(:) ! Gaussian longitudes with halo
758 real(kind=kind_real), allocatable :: lat_ggh(:) ! Gaussian latitudes with halo
759 real(kind=kind_real), allocatable :: lon_gg(:,:) ! Gaussian longitudes without halo
760 real(kind=kind_real), allocatable :: lat_gg(:,:) ! Gaussian latitudes without halo
761 
762 ! Check grid size
763 if( (geom%isc/=self%isc).or.(geom%iec/=self%iec) &
764 &.or.(geom%jsc/=self%jsc).or.(geom%jec/=self%jec)) then
765  call abor1_ftn("fv3jedi_linvarcha_nmcbal_mod.bump_init_gaugrid:&
766 & grid does not match that in the geometry")
767 end if
768 
769 ! Cubed-sphere grid
770 self%ngrid_cs = (geom%iec-geom%isc+1)*(geom%jec-geom%jsc+1)
771 allocate(lon_cs(self%ngrid_cs))
772 allocate(lat_cs(self%ngrid_cs))
773 jnode = 0
774 do jy=geom%jsc,geom%jec
775  do jx=geom%isc,geom%iec
776  jnode = jnode+1
777  lon_cs(jnode) = geom%grid_lon(jx,jy)*rad2deg
778  lat_cs(jnode) = geom%grid_lat(jx,jy)*rad2deg
779  end do
780 end do
781 
782 ! Gaussian grid with and without halo
783 self%ngrid_ggh = self%gg%nlat*self%gg%nlon
784 self%ngrid_gg = (self%gg%nlat-self%hy*2)*(self%gg%nlon-self%hx*2)
785 allocate(lon_ggh(self%ngrid_ggh))
786 allocate(lat_ggh(self%ngrid_ggh))
787 allocate(lon_gg(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy))
788 allocate(lat_gg(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy))
789 jnode = 0
790 do jy=1,self%gg%nlat
791  do jx=1,self%gg%nlon
792  jnode = jnode+1
793  lon_ggh(jnode) = self%gg%rlons(jx)*rad2deg
794  lat_ggh(jnode) = self%gg%rlats(jy)*rad2deg
795  end do
796 end do
797 do jy=1+self%hy,self%gg%nlat-self%hy
798  do jx=1+self%hx,self%gg%nlon-self%hx
799  lon_gg(jx,jy) = self%gg%rlons(jx)
800  lat_gg(jx,jy) = self%gg%rlats(jy)
801  end do
802 end do
803 
804 ! BUMP setup
805 call self%c2g%setup(geom%f_comm, &
806 & geom%isc,geom%iec,geom%jsc,geom%jec,geom%npz, &
807 & geom%grid_lon(geom%isc:geom%iec,geom%jsc:geom%jec), &
808 & geom%grid_lat(geom%isc:geom%iec,geom%jsc:geom%jec), &
809 & self%ngrid_ggh,lon_ggh,lat_ggh)
810 call self%g2c%setup(geom%f_comm, &
811 & 1+self%hx,self%gg%nlon-self%hx,1+self%hy,self%gg%nlat-self%hy,geom%npz, &
812 & lon_gg(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy), &
813 & lat_gg(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy), &
814 & self%ngrid_cs,lon_cs,lat_cs)
815 
816 ! Release memory
817 deallocate(lon_cs,lat_cs)
818 deallocate(lon_ggh,lat_ggh)
819 deallocate(lon_gg,lat_gg)
820 
821 end subroutine bump_init_gaugrid
822 
823 ! ------------------------------------------------------------------------------
824 ! read NMC balance operator girds from NetCDF
825 subroutine read_nmcbalance_grid(self)
826 
827 implicit none
828 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
829 
830 integer :: iunit,ierr,ncid,dimid
831 integer :: grid(3)
832 character(len=128) :: log_grid
833 character(len=16) :: nlat_c,nlon_c,nlev_c
834 
835 if(self%mype==0) then
836 ! Open NetCDF
837  call nccheck(nf90_open(trim(self%path_to_nmcbalance_coeffs),nf90_nowrite,ncid), &
838  & "nf90_open "//trim(self%path_to_nmcbalance_coeffs))
839 ! Get grid
840  call nccheck(nf90_inq_dimid(ncid,"nlat",dimid), "nf90_inq_dimid nlat")
841  call nccheck(nf90_inquire_dimension(ncid,dimid,len=grid(1)), &
842  & "nf90_inquire_dimension nlat" )
843  call nccheck(nf90_inq_dimid(ncid,"nlon",dimid), "nf90_inq_dimid nlon")
844  call nccheck(nf90_inquire_dimension(ncid,dimid,len=grid(2)), &
845  & "nf90_inquire_dimension nlon" )
846  call nccheck(nf90_inq_dimid(ncid,"nlev",dimid), "nf90_inq_dimid nlev")
847  call nccheck(nf90_inquire_dimension(ncid,dimid,len=grid(3)), &
848 & "nf90_inquire_dimension nlev" )
849 
850 ! Close NetCDF
851  call nccheck(nf90_close(ncid),"nf90_close")
852 end if
853 call self%geom_cs%f_comm%broadcast(grid,0)
854 if(grid(3)/=self%npz) then
855  call abor1_ftn("fv3jedi_linvarcha_nmcbal_mod.read_nmcbalance_grid:&
856 & nlev must be the same as npz on FV3 geometry")
857 end if
858 self%ny = grid(1)
859 self%nx = grid(2)
860 self%nz = grid(3)
861 if(self%mype==0) then
862  write(nlat_c,*) grid(1); write(nlon_c,*) grid(2); write(nlev_c,*) grid(3);
863  write(log_grid,*) "NMC balance operalor grid size : nx=",&
864  & trim(adjustl(nlon_c)), &
865  & ",ny=",trim(adjustl(nlat_c)), &
866  & ",nz=",trim(adjustl(nlev_c))
867  write(6,'(A)') log_grid
868 end if
869 
870 end subroutine read_nmcbalance_grid
871 
872 ! ------------------------------------------------------------------------------
873 ! read latlon from NetCDF
874 subroutine read_nmcbalance_latlon(self)
875 
876 implicit none
877 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
878 
879 integer :: iunit,ierr,ncid,varid
880 integer :: mm1,jx,i,j,k
881 
882 real(kind=kind_real),allocatable :: rlats(:)
883 real(kind=kind_real),allocatable :: rlons(:)
884 
885 allocate(rlats(self%glb%nlat))
886 allocate(rlons(self%glb%nlon))
887 
888 if(self%mype==0) then
889 ! Open NetCDF
890  call nccheck(nf90_open(trim(self%path_to_nmcbalance_coeffs),nf90_nowrite,ncid), &
891  & "nf90_open "//trim(self%path_to_nmcbalance_coeffs))
892 
893 ! Get coefficients
894  call nccheck(nf90_inq_varid(ncid,"lats",varid), "nf90_inq_varid lats")
895  call nccheck(nf90_get_var(ncid,varid,rlats),"nf90_get_var lats" )
896  call nccheck(nf90_inq_varid(ncid,"lons",varid), "nf90_inq_varid lons")
897  call nccheck(nf90_get_var(ncid,varid,rlons),"nf90_get_var lons" )
898 
899 ! Close NetCDF
900  call nccheck(nf90_close(ncid),"nf90_close")
901 end if
902 call self%geom_cs%f_comm%broadcast(rlats,0)
903 call self%geom_cs%f_comm%broadcast(rlons,0)
904 
905 do i=1,self%glb%nlon
906  self%glb%rlons(i) = rlons(i)*deg2rad
907 end do
908 do i=1,self%glb%nlat
909  self%glb%rlats(i) = rlats(i)*deg2rad
910 end do
911 
912 end subroutine read_nmcbalance_latlon
913 
914 ! ------------------------------------------------------------------------------
915 ! read NMC balance cofficients from NetCDF
916 subroutine read_nmcbalance_coeffs(self)
917 
918 implicit none
919 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
920 
921 integer :: iunit,ierr,ncid,varid
922 integer :: mm1,jx,i,j,k
923 
924 real(kind=r_single),allocatable :: agvin(:,:,:,:)
925 real(kind=r_single),allocatable :: wgvin(:,:,:)
926 real(kind=r_single),allocatable :: bvin(:,:,:)
927 
928 allocate(agvin(self%glb%nlat,self%glb%nlev,self%glb%nlev,1))
929 allocate(wgvin(self%glb%nlat,self%glb%nlev,1))
930 allocate(bvin(self%glb%nlat,self%glb%nlev,1))
931 
932 if(self%mype==0) then
933 ! Open NetCDF
934  call nccheck(nf90_open(trim(self%path_to_nmcbalance_coeffs),nf90_nowrite,ncid), &
935  & "nf90_open"//trim(self%path_to_nmcbalance_coeffs))
936 ! Get coefficients
937  call nccheck(nf90_inq_varid(ncid,"agvz",varid), "nf90_inq_varid agvz")
938  call nccheck(nf90_get_var(ncid,varid,agvin),"nf90_get_var agvz" )
939  call nccheck(nf90_inq_varid(ncid,"wgvz",varid), "nf90_inq_varid wgvz")
940  call nccheck(nf90_get_var(ncid,varid,wgvin),"nf90_get_var wgvz" )
941  call nccheck(nf90_inq_varid(ncid,"bvz",varid), "nf90_inq_varid bvz")
942  call nccheck(nf90_get_var(ncid,varid,bvin),"nf90_get_var bvz" )
943 
944 ! Close NetCDF
945  call nccheck(nf90_close(ncid),"nf90_close")
946 end if
947 call self%geom_cs%f_comm%broadcast(agvin,0)
948 call self%geom_cs%f_comm%broadcast(wgvin,0)
949 call self%geom_cs%f_comm%broadcast(bvin,0)
950 self%agvz = 0.0_kind_real
951 self%bvz = 0.0_kind_real
952 self%wgvz = 0.0_kind_real
953 mm1=self%mype+1
954 do k=1,self%gg%nlev
955  do j=1,self%gg%nlev
956  do i=1,self%gg%nlat
957  jx=self%jstry(mm1)+i-2
958  jx=max(jx,2)
959  jx=min(self%glb%nlat-1,jx)
960  self%agvz(i,j,k)=agvin(jx,j,k,1)
961  end do
962  end do
963  do i=1,self%gg%nlat
964  jx=self%jstry(mm1)+i-2
965  jx=max(jx,2)
966  jx=min(self%glb%nlat-1,jx)
967  self%wgvz(i,k)=wgvin(jx,k,1)
968  self%bvz(i,k)=bvin(jx,k,1)
969  end do
970 end do
971 deallocate(agvin,wgvin,bvin)
972 
973 end subroutine read_nmcbalance_coeffs
974 
975 ! ------------------------------------------------------------------------------
976 ! Interpolate cubed-sphere grid field to Gaussian gird using bump
977 subroutine field_interp_to_gaugrid(self)
978 
979 implicit none
980 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
981 
982 integer :: jvar,jnode,jx,jy,jz
983 real(kind_real),allocatable :: vec(:,:)
984 
985 ! Allocation
986 allocate(vec(self%ngrid_ggh,self%gg%nlev))
987 
988 do jvar=1,4
989  ! Initialization
990  vec = 0.0_kind_real
991 
992  ! Apply interpolation
993  call self%c2g%apply(self%npz, &
994  & self%fld(self%isc:self%iec,self%jsc:self%jec,1:self%npz,jvar), &
995  & self%ngrid_ggh,vec)
996 
997  ! Copy to Gaussian grid structure
998  do jz=1,self%gg%nlev
999  jnode = 0
1000  do jy=1,self%gg%nlat
1001  do jx=1,self%gg%nlon
1002  jnode = jnode+1
1003  self%gg%fld(jy,jx,jz,jvar) = vec(jnode,jz)
1004  end do
1005  end do
1006  end do
1007 end do
1008 
1009 ! Release memory
1010 deallocate(vec)
1011 
1012 end subroutine field_interp_to_gaugrid
1013 
1014 ! ------------------------------------------------------------------------------
1015 ! Interpolate Gaussian gird filed to cubed-sphere grid using bump
1017 
1018 implicit none
1019 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
1020 
1021 integer :: jvar,jx,jy,jz,jnode
1022 real(kind_real),allocatable :: fld(:,:,:),vec(:,:)
1023 
1024 ! Allocation
1025 allocate(fld(self%gg%nlon,self%gg%nlat,self%gg%nlev))
1026 allocate(vec(self%ngrid_cs,self%npz))
1027 
1028 do jvar=1,4
1029  ! Copy from Gaussian grid structure
1030  fld = 0.0_kind_real
1031  do jz=1,self%gg%nlev
1032  do jy=1+self%hy,self%gg%nlat-self%hy
1033  do jx=1+self%hx,self%gg%nlon-self%hx
1034  fld(jx,jy,jz) = self%gg%fld(jy,jx,jz,jvar)
1035  end do
1036  end do
1037  end do
1038 
1039 
1040  ! Apply interpolation
1041  call self%g2c%apply(self%gg%nlev, &
1042  & fld(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy,1:self%gg%nlev), &
1043  & self%ngrid_cs,vec)
1044 
1045  ! Copy to cubed-spere structure
1046  do jz=1,self%npz
1047  jnode = 0
1048  do jy=self%jsc,self%jec
1049  do jx=self%isc,self%iec
1050  jnode = jnode+1
1051  self%fld(jx,jy,jz,jvar) = vec(jnode,jz)
1052  end do
1053  end do
1054  end do
1055 end do
1056 
1057 ! Release memory
1058 deallocate(fld)
1059 deallocate(vec)
1060 
1061 end subroutine field_interp_from_gaugrid
1062 
1063 ! ------------------------------------------------------------------------------
1064 
1066 
1067 implicit none
1068 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
1069 
1070 integer :: jvar,jnode,jx,jy,jz
1071 real(kind_real),allocatable :: vec(:,:)
1072 
1073 ! Allocation
1074 allocate(vec(self%ngrid_ggh,self%gg%nlev))
1075 
1076 do jvar=1,4
1077  ! Initialization
1078  vec = 0.0_kind_real
1079 
1080  ! Copy to Gaussian grid structure
1081  do jz=1,self%gg%nlev
1082  jnode = 0
1083  do jy=1,self%gg%nlat
1084  do jx=1,self%gg%nlon
1085  jnode = jnode+1
1086  vec(jnode,jz) = self%gg%fld(jy,jx,jz,jvar)
1087  end do
1088  end do
1089  end do
1090 
1091  ! Apply interpolation
1092  call self%c2g%apply_ad(self%npz, &
1093  & self%fld(self%isc:self%iec,self%jsc:self%jec,1:self%npz,jvar), &
1094  & self%ngrid_ggh,vec)
1095 
1096 end do
1097 
1098 ! Reset input field
1099 self%gg%fld = 0.0_kind_real
1100 
1101 ! Release memory
1102 deallocate(vec)
1103 
1104 end subroutine field_interp_to_gaugrid_ad
1105 
1106 ! ------------------------------------------------------------------------------
1107 
1109 
1110 implicit none
1111 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
1112 
1113 
1114 integer :: jvar,jx,jy,jz,jnode
1115 real(kind_real),allocatable :: fld(:,:,:),vec(:,:)
1116 
1117 ! Allocation
1118 allocate(fld(self%gg%nlon,self%gg%nlat,self%gg%nlev))
1119 allocate(vec(self%ngrid_cs,self%npz))
1120 
1121 ! Initialization
1122 self%gg%fld = 0.0_kind_real
1123 
1124 do jvar=1,4
1125  ! Copy to cubed-spere structure
1126  do jz=1,self%npz
1127  jnode = 0
1128  do jy=self%jsc,self%jec
1129  do jx=self%isc,self%iec
1130  jnode = jnode+1
1131  vec(jnode,jz) = self%fld(jx,jy,jz,jvar)
1132  end do
1133  end do
1134  end do
1135 
1136  ! Apply interpolation
1137  call self%g2c%apply_ad(self%gg%nlev, &
1138  & fld(1+self%hx:self%gg%nlon-self%hx,1+self%hy:self%gg%nlat-self%hy,1:self%gg%nlev), &
1139  & self%ngrid_cs,vec)
1140 
1141  ! Copy from Gaussian grid structure
1142  do jz=1,self%gg%nlev
1143  do jy=1+self%hy,self%gg%nlat-self%hy
1144  do jx=1+self%hx,self%gg%nlon-self%hx
1145  self%gg%fld(jy,jx,jz,jvar) = self%gg%fld(jy,jx,jz,jvar)+fld(jx,jy,jz)
1146  end do
1147  end do
1148  end do
1149  fld = 0.0_kind_real
1150 end do
1151 
1152 ! Reset input field
1153 self%fld = 0.0_kind_real
1154 
1155 ! Release memory
1156 deallocate(fld)
1157 deallocate(vec)
1158 
1159 end subroutine field_interp_from_gaugrid_ad
1160 
1161 ! ------------------------------------------------------------------------------
1162 ! Apply balance operator
1163 ! This subroutine was migrated from gsi/balmod.F90
1164 subroutine balance(self)
1165 
1166 implicit none
1167 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
1168 integer :: i,j,k,l
1169 
1170 ! Add contribution from streamfunction and unbalanced vp
1171 ! to surface pressure.
1172 do k=1,self%gg%nlev
1173  do i=1,self%gg%nlon
1174  do j=1,self%gg%nlat
1175  self%ps(j,i)=self%ps(j,i)+self%wgvz(j,k)*self%psi(j,i,k)
1176  end do
1177  end do
1178 end do
1179 
1180 do k=1,self%gg%nlev
1181 ! Add contribution from streamfunction to veloc. potential
1182  do i=1,self%gg%nlon
1183  do j=1,self%gg%nlat
1184  self%chi(j,i,k)=self%chi(j,i,k)+self%bvz(j,k)*self%psi(j,i,k)
1185  end do
1186  end do
1187 
1188 ! Add contribution from streamfunction to unbalanced temperature.
1189  do l=1,self%gg%nlev
1190  do i=1,self%gg%nlon
1191  do j=1,self%gg%nlat
1192  self%tv(j,i,k)=self%tv(j,i,k)+self%agvz(j,k,l)*self%psi(j,i,l)
1193  end do
1194  end do
1195  end do
1196 end do
1197 
1198 end subroutine balance
1199 
1200 ! ------------------------------------------------------------------------------
1201 ! Adjoint of balance operator
1202 subroutine tbalance(self)
1203 
1204 implicit none
1205 type(fv3jedi_linvarcha_nmcbal), intent(inout) :: self
1206 integer :: i,j,k,l
1207 
1208 do k=1,self%gg%nlev
1209 ! Adjoint of contribution to temperature from streamfunction.
1210  do l=1,self%gg%nlev
1211  do i=1,self%gg%nlon
1212  do j=1,self%gg%nlat
1213  self%psi(j,i,k)=self%psi(j,i,k)+self%agvz(j,l,k)*self%tv(j,i,l)
1214  end do
1215  end do
1216  end do
1217 
1218 ! Adjoint of contribution to velocity potential from streamfunction.
1219  do i=1,self%gg%nlon
1220  do j=1,self%gg%nlat
1221  self%psi(j,i,k)=self%psi(j,i,k)+self%bvz(j,k)*self%chi(j,i,k)
1222  end do
1223  end do
1224 end do
1225 
1226 ! Adjoint of streamfunction and unbalanced velocity potential
1227 ! contribution to surface pressure.
1228 do k=1,self%gg%nlev
1229  do i=1,self%gg%nlon
1230  do j=1,self%gg%nlat
1231  self%psi(j,i,k)=self%psi(j,i,k)+self%wgvz(j,k)*self%ps(j,i)
1232  end do
1233  end do
1234 end do
1235 
1236 end subroutine tbalance
1237 
1238 ! ------------------------------------------------------------------------------
1239 ! Use to file format change from binary to NetCDF for more general reading
1240 subroutine bi2nc(path_to_gsi_bal_coeffs)
1241 implicit none
1242 
1243 character(len=*), intent(in ) :: path_to_gsi_bal_coeffs
1244 
1245 integer :: iunit,ierr
1246 integer :: nlev,nlat,nlon
1247 integer :: fileopts, ncid, vc, varid(10)
1248 integer :: x_dimid,y_dimid,z_dimid,t_dimid
1249 integer,allocatable :: v_dimids(:)
1250 real(kind=kind_real),allocatable :: lats(:),lons(:)
1251 integer,allocatable :: zk(:)
1252 integer :: i,j,k
1253 
1254 character(len=64) :: nlat_c,nlev_c
1255 character(len=128) :: ncname
1256 real(kind=r_single),allocatable :: agvin(:,:,:,:)
1257 real(kind=r_single),allocatable :: wgvin(:,:,:)
1258 real(kind=r_single),allocatable :: bvin(:,:,:)
1259 type(gaussian_grid) :: gauss
1260 
1261 iunit=get_fileunit()
1262 open(iunit,file=trim(path_to_gsi_bal_coeffs),form='unformatted', &
1263 & convert='big_endian',status='old',iostat=ierr)
1264 call check_iostat(ierr,"open balance coeffs header")
1265 rewind(iunit)
1266 read(iunit,iostat=ierr) nlev,nlat,nlon
1267 
1268 gauss%nlat = nlat
1269 gauss%nlon = nlon
1270 gauss%nlev = nlev
1271 gauss%nvar = 1
1272 call gauss%create()
1273 call gauss%calc_glb_latlon()
1274 
1275 allocate(lats(nlat))
1276 do j=1,nlat
1277  lats(j)=gauss%rlats(j)*rad2deg
1278 end do
1279 allocate(lons(nlon))
1280 do i=1,nlon
1281  lons(i)=gauss%rlons(i)*rad2deg
1282 end do
1283 allocate(zk(nlev))
1284 do k=1,nlev
1285  zk(k)=k
1286 end do
1287 
1288 allocate(agvin(nlat,nlev,nlev,1))
1289 allocate(wgvin(nlat,nlev,1))
1290 allocate(bvin(nlat,nlev,1))
1291 read(iunit,iostat=ierr) agvin,bvin,wgvin
1292 close(iunit)
1293 
1294 fileopts = ior(nf90_netcdf4, nf90_mpiio)
1295 
1296 ncid = 1
1297 write(nlev_c,*) nlev; write(nlat_c,*) nlat
1298 write(ncname,*) "global_berror.l",trim(adjustl(nlev_c)),"y",trim(adjustl(nlat_c)),".nc"
1299 call nccheck(nf90_create(trim(adjustl(ncname)),fileopts,ncid),'nf90_create')
1300 
1301 call nccheck(nf90_def_dim(ncid,'nlat',nlat,y_dimid),'nf90_def_dim nlat')
1302 call nccheck(nf90_def_dim(ncid,'nlon',nlon,x_dimid),'nf90_def_dim nlon')
1303 call nccheck(nf90_def_dim(ncid,'nlev',nlev,z_dimid),'nf90_def_dim nlev')
1304 call nccheck(nf90_def_dim(ncid,'time', 1,t_dimid),'nf90_def_dim time')
1305 
1306 vc = 1
1307 call nccheck(nf90_def_var(ncid,"lats",nf90_double,y_dimid,varid(vc)),"nf90_def_var lats")
1308 call nccheck(nf90_put_att(ncid,varid(vc),"long_name","latitude"))
1309 call nccheck(nf90_put_att(ncid,varid(vc),"units","degrees_north"))
1310 vc = 2
1311 call nccheck(nf90_def_var(ncid,"lons",nf90_double,x_dimid,varid(vc)),"nf90_def_var lons")
1312 call nccheck(nf90_put_att(ncid,varid(vc),"long_name","longitude"))
1313 call nccheck(nf90_put_att(ncid,varid(vc),"units","degrees_west"))
1314 vc = 3
1315 call nccheck(nf90_def_var(ncid,"level",nf90_int,z_dimid,varid(vc)),"nf90_def_var level")
1316 call nccheck(nf90_put_att(ncid,varid(vc),"long_name","vertical level"))
1317 call nccheck(nf90_put_att(ncid,varid(vc),"units","none"))
1318 vc = 4
1319 call nccheck(nf90_def_var(ncid,"time",nf90_int,t_dimid,varid(vc)),"nf90_def_var time")
1320 call nccheck(nf90_put_att(ncid,varid(vc),"long_name","time"),"nf90_def_var time long_name")
1321 
1322 vc = 5
1323 allocate(v_dimids(4))
1324 v_dimids(:) = (/y_dimid,z_dimid,z_dimid,t_dimid/)
1325 call nccheck(nf90_def_var(ncid,'agvz',nf90_float,v_dimids,varid(vc)),'nf90_def_var agvz')
1326 call nccheck(nf90_put_att(ncid,varid(vc), &
1327 & "long_name","projection_of_streamfunction_onto_balanced_temperature"))
1328 call nccheck(nf90_put_att(ncid,varid(vc),"units","K s m-2"))
1329 deallocate(v_dimids)
1330 vc = 6
1331 allocate(v_dimids(3))
1332 v_dimids(:) = (/y_dimid,z_dimid,t_dimid/)
1333 call nccheck(nf90_def_var(ncid,'bvz',nf90_float,v_dimids,varid(vc)),'nf90_def_var bvz')
1334 call nccheck(nf90_put_att(ncid,varid(vc), &
1335 & "long_name","projection_of_streamfunction_onto_balanced_velocity_potential"))
1336 call nccheck(nf90_put_att(ncid,varid(vc),"units","none"))
1337 vc = 7
1338 call nccheck(nf90_def_var(ncid,'wgvz',nf90_float,v_dimids,varid(vc)),'nf90_def_var wgvz')
1339 call nccheck(nf90_put_att(ncid,varid(vc), &
1340 & "long_name","projection_of_streamfunction_onto_balanced_surface_pressure"))
1341 call nccheck(nf90_put_att(ncid,varid(vc),"units","Pa s m-2"))
1342 deallocate(v_dimids)
1343 
1344 call nccheck(nf90_enddef(ncid),"nf90_enddef")
1345 
1346 vc = 1
1347 call nccheck(nf90_put_var(ncid,varid(vc),lats),"nf90_put_var lats")
1348 vc = 2
1349 call nccheck(nf90_put_var(ncid,varid(vc),lons),"nf90_put_var lons")
1350 vc = 3
1351 call nccheck(nf90_put_var(ncid,varid(vc),zk),"nf90_put_var level")
1352 vc = 4
1353 call nccheck(nf90_put_var(ncid,varid(vc),1),"nf90_put_var time")
1354 
1355 vc = 5
1356 call nccheck(nf90_put_var(ncid,varid(vc),agvin),"nf90_put_var agvz")
1357 vc = 6
1358 call nccheck(nf90_put_var(ncid,varid(vc),bvin),"nf90_put_var bvz")
1359 vc = 7
1360 call nccheck(nf90_put_var(ncid,varid(vc),wgvin),"nf90_put_var wgvz")
1361 
1362 call nccheck(nf90_close(ncid),'nf90_close')
1363 
1364 deallocate(lats)
1365 deallocate(zk)
1366 deallocate(agvin,wgvin,bvin)
1367 
1368 end subroutine bi2nc
1369 
1370 ! ------------------------------------------------------------------------------
1371 ! get unused file unit
1372 integer function get_fileunit(iunit_in) result(iunit)
1373 
1374 implicit none
1375 integer,intent(in),optional :: iunit_in
1376 
1377 logical :: lopened, lexist
1378 integer,parameter :: iunit_str=11, iunit_end=99
1379 integer :: i
1380 
1381 if(present(iunit_in)) then
1382  inquire(unit=iunit_in,opened=lopened,exist=lexist)
1383  if(lexist.and.(.not.lopened)) iunit=iunit_in
1384  return
1385 end if
1386 
1387 do i=iunit_str,iunit_end
1388  inquire(unit=i,opened=lopened,exist=lexist)
1389  if(lexist.and.(.not.lopened)) then
1390  iunit=i
1391  exit
1392  end if
1393 end do
1394 
1395 end function get_fileunit
1396 
1397 ! ------------------------------------------------------------------------------
1398 ! check I/O return code
1399 subroutine check_iostat(ierr,mess)
1400 
1401 implicit none
1402 integer,intent(in) :: ierr
1403 character(len=*),intent(in) :: mess
1404 
1405 character(len=256) :: abort_log
1406 
1407 write(abort_log,'(3A,I3)') "IO Error : ",trim(mess)," : iostat=",ierr
1408 if(ierr/=0) then
1409  call abor1_ftn(trim(adjustl(abort_log)))
1410 end if
1411 
1412 end subroutine check_iostat
1413 
1414 ! ------------------------------------------------------------------------------
1415 
fv3jedi_linvarcha_nmcbal_mod::create
subroutine, public create(self, geom, bg, fg, conf)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:106
fv3jedi_state_mod::fv3jedi_state
Fortran derived type to hold FV3JEDI state.
Definition: fv3jedi_state_mod.F90:30
fv3jedi_field_mod
Definition: fv3jedi_field_mod.f90:6
moisture_vt_mod
Definition: moisture_variables_mod.f90:6
fv3jedi_linvarcha_nmcbal_mod::get_local_dims_
subroutine get_local_dims_(dim_world, dim, ndes)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:702
fv3jedi_linvarcha_nmcbal_mod::multiplyinverse
subroutine, public multiplyinverse(self, geom, xbal, xuba)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:463
temperature_vt_mod::t_to_tv
subroutine, public t_to_tv(geom, t, q, tv)
Definition: temperature_variables_mod.f90:27
fv3jedi_netcdf_utils_mod
Definition: fv3jedi_netcdf_utils_mod.F90:6
fv3jedi_linvarcha_nmcbal_mod::read_nmcbalance_coeffs
subroutine read_nmcbalance_coeffs(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:917
fv3jedi_linvarcha_nmcbal_mod::check_iostat
subroutine check_iostat(ierr, mess)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1400
fv3jedi_linvarcha_nmcbal_mod::multiplyinverseadjoint
subroutine, public multiplyinverseadjoint(self, geom, xuba, xbal)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:509
fv3jedi_linvarcha_nmcbal_mod::multiply
subroutine, public multiply(self, geom, xuba, xbal)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:293
fv3jedi_linvarcha_nmcbal_mod::deter_subdomain
subroutine deter_subdomain(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:555
fv3jedi_bump_interp_mod::fv3jedi_bump_interp
Definition: fv3jedi_bump_interp_mod.f90:31
fv3jedi_state_mod
Definition: fv3jedi_state_mod.F90:6
fv3jedi_constants_mod::rad2deg
real(kind=kind_real), parameter, public rad2deg
Definition: fv3jedi_constants_mod.f90:13
fv3jedi_field_mod::copy_subset
subroutine, public copy_subset(field_in, field_ou, not_copied)
Definition: fv3jedi_field_mod.f90:236
fv3jedi_geom_mod
Fortran module handling geometry for the FV3 model.
Definition: fv3jedi_geom_mod.f90:8
fv3jedi_linvarcha_nmcbal_mod::read_nmcbalance_latlon
subroutine read_nmcbalance_latlon(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:875
fv3jedi_increment_mod
Definition: fv3jedi_increment_mod.F90:6
fv3jedi_linvarcha_nmcbal_mod::deter_subdomain_withlayout
subroutine deter_subdomain_withlayout(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:570
fv3jedi_linvarcha_nmcbal_mod::balance
subroutine balance(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1165
fv3jedi_linvarcha_nmcbal_mod::bi2nc
subroutine bi2nc(path_to_gsi_bal_coeffs)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1241
fv3jedi_linvarcha_nmcbal_mod::deter_subdomain_nolayout
subroutine deter_subdomain_nolayout(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:633
fv3jedi_linvarcha_nmcbal_mod::read_nmcbalance_grid
subroutine read_nmcbalance_grid(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:826
fv3jedi_linvarcha_nmcbal_mod::delete
subroutine, public delete(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:258
fv3jedi_geom_mod::fv3jedi_geom
Fortran derived type to hold geometry data for the FV3JEDI model.
Definition: fv3jedi_geom_mod.f90:46
fv3jedi_linvarcha_nmcbal_mod::field_interp_to_gaugrid
subroutine field_interp_to_gaugrid(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:978
fv3jedi_netcdf_utils_mod::nccheck
subroutine, public nccheck(status, iam)
Definition: fv3jedi_netcdf_utils_mod.F90:21
wind_vt_mod
Definition: wind_variables_mod.f90:6
fv3jedi_linvarcha_nmcbal_mod::bump_init_gaugrid
subroutine bump_init_gaugrid(self, geom)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:748
fv3jedi_linvarcha_nmcbal_mod::field_interp_to_gaugrid_ad
subroutine field_interp_to_gaugrid_ad(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1066
temperature_vt_mod
Definition: temperature_variables_mod.f90:6
fv3jedi_constants_mod
Definition: fv3jedi_constants_mod.f90:6
fv3jedi_linvarcha_nmcbal_mod::tbalance
subroutine tbalance(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1203
fv3jedi_linvarcha_nmcbal_mod::field_interp_from_gaugrid_ad
subroutine field_interp_from_gaugrid_ad(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1109
wind_vt_mod::psichi_to_uava
subroutine, public psichi_to_uava(geom, psi, chi, ua, va)
Definition: wind_variables_mod.f90:111
pressure_vt_mod
Definition: pressure_variables_mod.f90:6
temperature_vt_mod::tv_to_t_ad
subroutine, public tv_to_t_ad(geom, tv, tv_ad, q, q_ad, t_ad)
Definition: temperature_variables_mod.f90:107
wind_vt_mod::psichi_to_uava_adm
subroutine, public psichi_to_uava_adm(geom, psi_ad, chi_ad, ua_ad, va_ad)
Definition: wind_variables_mod.f90:264
moisture_vt_mod::get_qsat
subroutine, public get_qsat(geom, delp, t, q, qsat)
Definition: moisture_variables_mod.f90:486
fv3jedi_linvarcha_nmcbal_mod::get_fileunit
integer function get_fileunit(iunit_in)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1373
fv3jedi_linvarcha_nmcbal_mod::field_interp_from_gaugrid
subroutine field_interp_from_gaugrid(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:1017
moisture_vt_mod::rh_to_q_ad
subroutine, public rh_to_q_ad(geom, qsat, rh, q)
Definition: moisture_variables_mod.f90:373
fv3jedi_linvarcha_nmcbal_mod
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:6
fv3jedi_constants_mod::deg2rad
real(kind=kind_real), parameter, public deg2rad
Definition: fv3jedi_constants_mod.f90:14
fv3jedi_bump_interp_mod
Definition: fv3jedi_bump_interp_mod.f90:7
fv3jedi_kinds_mod::kind_real
integer, parameter, public kind_real
Definition: fv3jedi_kinds_mod.f90:14
fv3jedi_linvarcha_nmcbal_mod::multiplyadjoint
subroutine, public multiplyadjoint(self, geom, xbal, xuba)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:375
fv3jedi_linvarcha_nmcbal_mod::fv3jedi_linvarcha_nmcbal
Fortran derived type to hold configuration data for the B mat variable change.
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:46
fv3jedi_kinds_mod
Definition: fv3jedi_kinds_mod.f90:6
fv3jedi_constants_mod::pi
real(kind=kind_real), parameter, public pi
Definition: fv3jedi_constants_mod.f90:16
moisture_vt_mod::rh_to_q_tl
subroutine, public rh_to_q_tl(geom, qsat, rh, q)
Definition: moisture_variables_mod.f90:359
fv3jedi_linvarcha_nmcbal_mod::r_single
integer, parameter r_single
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:35
fv3jedi_linvarcha_nmcbal_mod::set_gaugrid_latlon
subroutine set_gaugrid_latlon(self)
Definition: fv3jedi_linvarcha_nmcbal_mod.f90:720
temperature_vt_mod::tv_to_t_tl
subroutine, public tv_to_t_tl(geom, tv, tv_tl, q, q_tl, t_tl)
Definition: temperature_variables_mod.f90:91
fv3jedi_increment_mod::fv3jedi_increment
Definition: fv3jedi_increment_mod.F90:34