FV3 Bundle
type_diag_blk.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_diag_blk
3 ! Purpose: diagnostic block derived type
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
7 !----------------------------------------------------------------------
9 
10 use netcdf
11 !$ use omp_lib
12 use tools_const, only: msvali,msvalr
13 use tools_fit, only: fast_fit,ver_fill
15 use tools_kinds, only: kind_real
17 use tools_nc, only: ncfloat
18 use tools_repro, only: sup
19 use type_avg_blk, only: avg_blk_type
20 use type_bpar, only: bpar_type
21 use type_geom, only: geom_type
22 use type_minim, only: minim_type
23 use type_mpl, only: mpl_type
24 use type_nam, only: nam_type
25 use type_samp, only: samp_type
26 
27 implicit none
28 
29 integer,parameter :: nsc = 50 ! Number of iterations for the scaling optimization
30 logical :: lprt = .false. ! Optimization print
31 real(kind_real),parameter :: maxfactor = 2.0_kind_real ! Maximum factor for diagnostics with respect to the origin
32 
33 ! Diagnostic block derived type
35  integer :: ic2a ! Local index
36  integer :: ib ! Block index
37  character(len=1024) :: name ! Name
38  logical :: double_fit ! Double fit flag
39 
40  real(kind_real),allocatable :: raw(:,:,:) ! Raw diagnostic
41  real(kind_real),allocatable :: raw_coef_ens(:) ! Raw ensemble coefficient
42  real(kind_real) :: raw_coef_sta ! Raw static coefficient
43  real(kind_real),allocatable :: fit(:,:,:) ! Fit
44  real(kind_real),allocatable :: fit_rh(:) ! Horizontal fit support radius
45  real(kind_real),allocatable :: fit_rv(:) ! Vertical fit support radius
46  real(kind_real),allocatable :: fit_rv_rfac(:) ! Vertical fit support radius ratio for the positive component (for double-radius fit)
47  real(kind_real),allocatable :: fit_rv_coef(:) ! Vertical fit coefficient (for double-radius fit)
48  real(kind_real),allocatable :: distv(:,:) ! Reduced vertical distance
49 contains
50  procedure :: alloc => diag_blk_alloc
51  procedure :: dealloc => diag_blk_dealloc
52  procedure :: write => diag_blk_write
53  procedure :: normalization => diag_blk_normalization
54  procedure :: fitting => diag_blk_fitting
55  procedure :: localization => diag_blk_localization
56  procedure :: hybridization => diag_blk_hybridization
57  procedure :: dualens => diag_blk_dualens
58 end type diag_blk_type
59 
60 private
61 public :: diag_blk_type
62 
63 contains
64 
65 !----------------------------------------------------------------------
66 ! Subroutine: diag_blk_alloc
67 ! Purpose: diagnostic block data allocation
68 !----------------------------------------------------------------------
69 subroutine diag_blk_alloc(diag_blk,nam,geom,bpar,samp,ic2a,ib,prefix,double_fit)
70 
71 implicit none
72 
73 ! Passed variables
74 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block
75 type(nam_type),intent(in) :: nam ! Namelist
76 type(geom_type),intent(in) :: geom ! Geometry
77 type(bpar_type),intent(in) :: bpar ! Block parameters
78 type(samp_type),intent(in) :: samp ! Sampling
79 integer,intent(in) :: ic2a ! Local index
80 integer,intent(in) :: ib ! Block index
81 character(len=*),intent(in) :: prefix ! Block prefix
82 logical,intent(in) :: double_fit ! Double fit
83 
84 ! Local variables
85 integer :: ic0,ic2,il0,jl0
86 real(kind_real) :: vunit(geom%nl0)
87 
88 ! Set attributes
89 diag_blk%ic2a = ic2a
90 diag_blk%ib = ib
91 diag_blk%name = trim(prefix)//'_'//trim(bpar%blockname(ib))
92 diag_blk%double_fit = double_fit
93 
94 ! Allocation
95 allocate(diag_blk%raw_coef_ens(geom%nl0))
96 if ((ic2a==0).or.nam%local_diag) allocate(diag_blk%raw(nam%nc3,bpar%nl0r(ib),geom%nl0))
97 
98 ! Initialization
99 call msr(diag_blk%raw_coef_ens)
100 if ((ic2a==0).or.nam%local_diag) then
101  call msr(diag_blk%raw)
102  call msr(diag_blk%raw_coef_sta)
103 end if
104 
105 if (((ic2a==0).or.nam%local_diag).and.(trim(nam%minim_algo)/='none')) then
106  ! Allocation
107  allocate(diag_blk%fit(nam%nc3,bpar%nl0r(ib),geom%nl0))
108  allocate(diag_blk%fit_rh(geom%nl0))
109  allocate(diag_blk%fit_rv(geom%nl0))
110  if (diag_blk%double_fit) then
111  allocate(diag_blk%fit_rv_rfac(geom%nl0))
112  allocate(diag_blk%fit_rv_coef(geom%nl0))
113  end if
114  allocate(diag_blk%distv(geom%nl0,geom%nl0))
115 
116  ! Initialization
117  call msr(diag_blk%fit)
118  call msr(diag_blk%fit_rh)
119  call msr(diag_blk%fit_rv)
120  if (diag_blk%double_fit) then
121  call msr(diag_blk%fit_rv_rfac)
122  call msr(diag_blk%fit_rv_coef)
123  end if
124  call msr(diag_blk%distv)
125 
126  ! Vertical unit
127  if (ic2a==0) then
128  vunit = geom%vunitavg
129  else
130  ic2 = samp%c2a_to_c2(ic2a)
131  ic0 = samp%c2_to_c0(ic2)
132  vunit = geom%vunit(ic0,:)
133  end if
134 
135  ! Vertical distance
136  do il0=1,geom%nl0
137  do jl0=1,geom%nl0
138  diag_blk%distv(jl0,il0) = abs(vunit(il0)-vunit(jl0))
139  end do
140  end do
141 end if
142 
143 end subroutine diag_blk_alloc
144 
145 !----------------------------------------------------------------------
146 ! Subroutine: diag_blk_dealloc
147 ! Purpose: diagnostic block data deallocation
148 !----------------------------------------------------------------------
149 subroutine diag_blk_dealloc(diag_blk)
151 implicit none
152 
153 ! Passed variables
154 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block
155 
156 ! Release memory
157 if (allocated(diag_blk%raw)) deallocate(diag_blk%raw)
158 if (allocated(diag_blk%raw_coef_ens)) deallocate(diag_blk%raw_coef_ens)
159 if (allocated(diag_blk%fit)) deallocate(diag_blk%fit)
160 if (allocated(diag_blk%fit_rh)) deallocate(diag_blk%fit_rh)
161 if (allocated(diag_blk%fit_rv)) deallocate(diag_blk%fit_rv)
162 if (allocated(diag_blk%fit_rv_rfac)) deallocate(diag_blk%fit_rv_rfac)
163 if (allocated(diag_blk%fit_rv_coef)) deallocate(diag_blk%fit_rv_coef)
164 if (allocated(diag_blk%distv)) deallocate(diag_blk%distv)
165 
166 end subroutine diag_blk_dealloc
167 
168 !----------------------------------------------------------------------
169 ! Subroutine: diag_blk_write
170 ! Purpose: write a diagnostic
171 !----------------------------------------------------------------------
172 subroutine diag_blk_write(diag_blk,mpl,nam,geom,bpar,filename)
174 implicit none
175 
176 ! Passed variables
177 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block
178 type(mpl_type),intent(in) :: mpl ! MPI data
179 type(nam_type),intent(in) :: nam ! Namelist
180 type(geom_type),intent(in) :: geom ! Geometry
181 type(bpar_type),intent(in) :: bpar ! Block parameters
182 character(len=*),intent(in) :: filename ! File name
183 
184 ! Local variables
185 integer :: info,ncid,one_id,nc3_id,nl0r_id,nl0_1_id,nl0_2_id,disth_id,vunit_id
186 integer :: raw_id,raw_zs_id,raw_coef_ens_id,raw_coef_sta_id,l0rl0_to_l0_id
187 integer :: fit_id,fit_zs_id,fit_rh_id,fit_rv_id,fit_rv_rfac_id,fit_rv_coef_id
188 integer :: il0,jl0r,jl0
189 character(len=1024) :: subr = 'diag_blk_write'
190 
191 ! Associate
192 associate(ib=>diag_blk%ib,ic2a=>diag_blk%ic2a)
193 
194 ! Check if the file exists
195 info = nf90_create(trim(nam%datadir)//'/'//trim(filename),or(nf90_noclobber,nf90_64bit_offset),ncid)
196 if (info==nf90_noerr) then
197  ! Write namelist parameters
198  call nam%ncwrite(mpl,ncid)
199 else
200  ! Open file
201  call mpl%ncerr(subr,nf90_open(trim(nam%datadir)//'/'//trim(filename),nf90_write,ncid))
202 
203  ! Redef mode
204  call mpl%ncerr(subr,nf90_redef(ncid))
205 end if
206 
207 ! Define dimensions and variables if necessary
208 info = nf90_inq_dimid(ncid,'one',one_id)
209 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'one',1,one_id))
210 info = nf90_inq_dimid(ncid,'nc3',nc3_id)
211 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nc3',nam%nc3,nc3_id))
212 info = nf90_inq_dimid(ncid,'nl0r',nl0r_id)
213 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0r',bpar%nl0rmax,nl0r_id))
214 info = nf90_inq_dimid(ncid,'nl0_1',nl0_1_id)
215 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0_1',geom%nl0,nl0_1_id))
216 if (bpar%nl0rmax/=geom%nl0) then
217  info = nf90_inq_dimid(ncid,'nl0_2',nl0_2_id)
218  if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_dim(ncid,'nl0_2',geom%nl0,nl0_2_id))
219 end if
220 info = nf90_inq_varid(ncid,'disth',disth_id)
221 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_var(ncid,'disth',ncfloat,(/nc3_id/),disth_id))
222 info = nf90_inq_varid(ncid,'vunit',vunit_id)
223 if (info/=nf90_noerr) call mpl%ncerr(subr,nf90_def_var(ncid,'vunit',ncfloat,(/nl0_1_id/),vunit_id))
224 info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_raw_coef_ens',raw_coef_ens_id)
225 if (info/=nf90_noerr) then
226  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_raw_coef_ens',ncfloat,(/nl0_1_id/),raw_coef_ens_id))
227  call mpl%ncerr(subr,nf90_put_att(ncid,raw_coef_ens_id,'_FillValue',msvalr))
228 end if
229 if ((ic2a==0).or.nam%local_diag) then
230  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_raw',raw_id)
231  if (info/=nf90_noerr) then
232  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_raw',ncfloat,(/nc3_id,nl0r_id,nl0_1_id/),raw_id))
233  call mpl%ncerr(subr,nf90_put_att(ncid,raw_id,'_FillValue',msvalr))
234  end if
235  if (bpar%nl0rmax/=geom%nl0) then
236  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_raw_zs',raw_zs_id)
237  if (info/=nf90_noerr) then
238  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_raw_zs',ncfloat,(/nl0_2_id,nl0_1_id/),raw_zs_id))
239  call mpl%ncerr(subr,nf90_put_att(ncid,raw_zs_id,'_FillValue',msvalr))
240  end if
241  end if
242  if (isnotmsr(diag_blk%raw_coef_sta)) then
243  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_raw_coef_sta',raw_coef_sta_id)
244  if (info/=nf90_noerr) then
245  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_raw_coef_sta',ncfloat,(/one_id/),raw_coef_sta_id))
246  call mpl%ncerr(subr,nf90_put_att(ncid,raw_coef_sta_id,'_FillValue',msvalr))
247  end if
248  end if
249  if ((trim(nam%minim_algo)/='none').and.(isanynotmsr(diag_blk%fit))) then
250  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit',fit_id)
251  if (info/=nf90_noerr) then
252  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit',ncfloat,(/nc3_id,nl0r_id,nl0_1_id/),fit_id))
253  call mpl%ncerr(subr,nf90_put_att(ncid,fit_id,'_FillValue',msvalr))
254  end if
255  if (bpar%nl0rmax/=geom%nl0) then
256  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit_zs',fit_zs_id)
257  if (info/=nf90_noerr) then
258  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit_zs',ncfloat,(/nl0_2_id,nl0_1_id/),fit_zs_id))
259  call mpl%ncerr(subr,nf90_put_att(ncid,fit_zs_id,'_FillValue',msvalr))
260  end if
261  end if
262  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit_rh',fit_rh_id)
263  if (info/=nf90_noerr) then
264  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit_rh',ncfloat,(/nl0_1_id/),fit_rh_id))
265  call mpl%ncerr(subr,nf90_put_att(ncid,fit_rh_id,'_FillValue',msvalr))
266  end if
267  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit_rv',fit_rv_id)
268  if (info/=nf90_noerr) then
269  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit_rv',ncfloat,(/nl0_1_id/),fit_rv_id))
270  call mpl%ncerr(subr,nf90_put_att(ncid,fit_rv_id,'_FillValue',msvalr))
271  end if
272  if (diag_blk%double_fit) then
273  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit_rv_rfac',fit_rv_rfac_id)
274  if (info/=nf90_noerr) then
275  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit_rv_rfac',ncfloat,(/nl0_1_id/),fit_rv_rfac_id))
276  call mpl%ncerr(subr,nf90_put_att(ncid,fit_rv_rfac_id,'_FillValue',msvalr))
277  end if
278  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_fit_rv_coef',fit_rv_coef_id)
279  if (info/=nf90_noerr) then
280  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_fit_rv_coef',ncfloat,(/nl0_1_id/),fit_rv_coef_id))
281  call mpl%ncerr(subr,nf90_put_att(ncid,fit_rv_coef_id,'_FillValue',msvalr))
282  end if
283  end if
284  end if
285  info = nf90_inq_varid(ncid,trim(diag_blk%name)//'_l0rl0_to_l0',l0rl0_to_l0_id)
286  if (info/=nf90_noerr) then
287  call mpl%ncerr(subr,nf90_def_var(ncid,trim(diag_blk%name)//'_l0rl0_to_l0',nf90_int,(/nl0r_id,nl0_1_id/),l0rl0_to_l0_id))
288  call mpl%ncerr(subr,nf90_put_att(ncid,l0rl0_to_l0_id,'_FillValue',msvali))
289  end if
290 end if
291 
292 ! End definition mode
293 call mpl%ncerr(subr,nf90_enddef(ncid))
294 
295 ! Write variables
296 call mpl%ncerr(subr,nf90_put_var(ncid,disth_id,geom%disth(1:nam%nc3)))
297 call mpl%ncerr(subr,nf90_put_var(ncid,vunit_id,sum(geom%vunit,mask=geom%mask_c0,dim=1)/real(geom%nc0_mask,kind_real)))
298 call mpl%ncerr(subr,nf90_put_var(ncid,raw_coef_ens_id,diag_blk%raw_coef_ens))
299 if ((ic2a==0).or.nam%local_diag) then
300  call mpl%ncerr(subr,nf90_put_var(ncid,raw_id,diag_blk%raw))
301  if (bpar%nl0rmax/=geom%nl0) then
302  do il0=1,geom%nl0
303  do jl0r=1,bpar%nl0rmax
304  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
305  call mpl%ncerr(subr,nf90_put_var(ncid,raw_zs_id,diag_blk%raw(1,jl0r,il0),(/jl0,il0/)))
306  end do
307  end do
308  end if
309  if (isnotmsr(diag_blk%raw_coef_sta)) call mpl%ncerr(subr,nf90_put_var(ncid,raw_coef_sta_id,diag_blk%raw_coef_sta))
310  if ((trim(nam%minim_algo)/='none').and.(isanynotmsr(diag_blk%fit))) then
311  call mpl%ncerr(subr,nf90_put_var(ncid,fit_id,diag_blk%fit))
312  if (bpar%nl0rmax/=geom%nl0) then
313  do il0=1,geom%nl0
314  do jl0r=1,bpar%nl0rmax
315  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
316  call mpl%ncerr(subr,nf90_put_var(ncid,fit_zs_id,diag_blk%fit(1,jl0r,il0),(/jl0,il0/)))
317  end do
318  end do
319  end if
320  call mpl%ncerr(subr,nf90_put_var(ncid,fit_rh_id,diag_blk%fit_rh))
321  call mpl%ncerr(subr,nf90_put_var(ncid,fit_rv_id,diag_blk%fit_rv))
322  if (diag_blk%double_fit) then
323  call mpl%ncerr(subr,nf90_put_var(ncid,fit_rv_rfac_id,diag_blk%fit_rv_rfac))
324  call mpl%ncerr(subr,nf90_put_var(ncid,fit_rv_coef_id,diag_blk%fit_rv_coef))
325  end if
326  end if
327  call mpl%ncerr(subr,nf90_put_var(ncid,l0rl0_to_l0_id,bpar%l0rl0b_to_l0(:,:,ib)))
328 end if
329 
330 ! Close file
331 call mpl%ncerr(subr,nf90_close(ncid))
332 
333 ! End associate
334 end associate
335 
336 end subroutine diag_blk_write
337 
338 !----------------------------------------------------------------------
339 ! Subroutine: diag_blk_normalization
340 ! Purpose: compute diagnostic block normalization
341 !----------------------------------------------------------------------
342 subroutine diag_blk_normalization(diag_blk,geom,bpar,remove_max)
344 implicit none
345 
346 ! Passed variables
347 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block
348 type(geom_type),intent(in) :: geom ! Geometry
349 type(bpar_type),intent(in) :: bpar ! Block parameters
350 logical,intent(in),optional :: remove_max ! Remove excessive values
351 
352 ! Local variables
353 integer :: il0,jl0r,jl0,jc3
354 logical :: lremove_max
355 
356 ! Associate
357 associate(ib=>diag_blk%ib)
358 
359 ! Get diagonal values
360 do il0=1,geom%nl0
361  jl0r = bpar%il0rz(il0,ib)
362  if (isnotmsr(diag_blk%raw(1,jl0r,il0))) diag_blk%raw_coef_ens(il0) = diag_blk%raw(1,jl0r,il0)
363 end do
364 
365 ! Normalize
366 do il0=1,geom%nl0
367  do jl0r=1,bpar%nl0r(ib)
368  jl0 = bpar%l0rl0b_to_l0(jl0r,il0,ib)
369  do jc3=1,bpar%nc3(ib)
370  if (isnotmsr(diag_blk%raw(jc3,jl0r,il0)).and.isnotmsr(diag_blk%raw_coef_ens(il0)) &
371  & .and.isnotmsr(diag_blk%raw_coef_ens(jl0))) &
372  & diag_blk%raw(jc3,jl0r,il0) = diag_blk%raw(jc3,jl0r,il0)/sqrt(diag_blk%raw_coef_ens(il0)*diag_blk%raw_coef_ens(jl0))
373  end do
374  end do
375 end do
376 
377 ! Remove excessive values compared to the origin point
378 if (present(remove_max)) then
379  lremove_max = remove_max
380 else
381  lremove_max = .false.
382 end if
383 if (lremove_max) then
384  !$omp parallel do schedule(static) private(il0,jl0r,jc3)
385  do il0=1,geom%nl0
386  do jl0r=1,bpar%nl0r(ib)
387  do jc3=1,bpar%nc3(ib)
388  if (sup(diag_blk%raw(jc3,jl0r,il0),maxfactor)) call msr(diag_blk%raw(jc3,jl0r,il0))
389  end do
390  end do
391  end do
392  !$omp end parallel do
393 end if
394 
395 ! End associate
396 end associate
397 
398 end subroutine diag_blk_normalization
399 
400 !----------------------------------------------------------------------
401 ! Subroutine: diag_blk_fitting
402 ! Purpose: compute a semi-positive definite fit of a raw function
403 !----------------------------------------------------------------------
404 subroutine diag_blk_fitting(diag_blk,mpl,nam,geom,bpar,samp)
406 implicit none
407 
408 ! Passed variables
409 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block
410 type(mpl_type),intent(in) :: mpl ! MPI data
411 type(nam_type),intent(in) :: nam ! Namelist
412 type(geom_type),intent(in) :: geom ! Geometry
413 type(bpar_type),intent(in) :: bpar ! Block parameters
414 type(samp_type),intent(in) :: samp ! Sampling
415 
416 ! Local variables
417 integer :: ic2,ic0,il0,jl0r,offset,isc
418 real(kind_real) :: alpha,alpha_opt,mse,mse_opt
419 real(kind_real) :: vunit(geom%nl0),fit_rh(geom%nl0),fit_rv(geom%nl0)
420 real(kind_real),allocatable :: rawv(:),distv(:),fit(:,:,:)
421 type(minim_type) :: minim
422 
423 ! Associate
424 associate(ic2a=>diag_blk%ic2a,ib=>diag_blk%ib)
425 
426 ! Check
427 if (trim(nam%minim_algo)=='none') call mpl%abort('cannot compute fit if minim_algo = none')
428 
429 ! Allocation
430 allocate(rawv(bpar%nl0r(ib)))
431 allocate(distv(bpar%nl0r(ib)))
432 allocate(fit(nam%nc3,bpar%nl0r(ib),geom%nl0))
433 
434 ! Initialization
435 call msr(diag_blk%fit_rh)
436 call msr(diag_blk%fit_rv)
437 call msr(diag_blk%fit)
438 
439 ! Vertical unit
440 if (ic2a==0) then
441  vunit = geom%vunitavg
442 else
443  ic2 = samp%c2a_to_c2(ic2a)
444  ic0 = samp%c2_to_c0(ic2)
445  vunit = geom%vunit(ic0,:)
446 end if
447 
448 ! Fast fit
449 do il0=1,geom%nl0
450  ! Get zero separation level
451  jl0r = bpar%il0rz(il0,ib)
452 
453  ! Horizontal fast fit
454  call fast_fit(mpl,nam%nc3,1,geom%disth,diag_blk%raw(:,jl0r,il0),diag_blk%fit_rh(il0))
455 
456  ! Vertical fast fit
457  rawv = diag_blk%raw(1,:,il0)
458  distv = diag_blk%distv(bpar%l0rl0b_to_l0(:,il0,ib),il0)
459  call fast_fit(mpl,bpar%nl0r(ib),jl0r,distv,rawv,diag_blk%fit_rv(il0))
460 end do
461 
462 if (any(isnotmsr(diag_blk%fit_rh)).and.any(isnotmsr(diag_blk%fit_rv))) then
463  ! Fill missing values
464  call ver_fill(mpl,geom%nl0,vunit,diag_blk%fit_rh)
465  call ver_fill(mpl,geom%nl0,vunit,diag_blk%fit_rv)
466 
467  ! Vertically homogeneous case
468  if (nam%lhomh) diag_blk%fit_rh = sum(diag_blk%fit_rh,mask=isnotmsr(diag_blk%fit_rh)) &
469  & /real(count(isnotmsr(diag_blk%fit_rh)),kind_real)
470  if (nam%lhomv) diag_blk%fit_rv = sum(diag_blk%fit_rv,mask=isnotmsr(diag_blk%fit_rv)) &
471  & /real(count(isnotmsr(diag_blk%fit_rv)),kind_real)
472 
473  ! Double-fit default parameters
474  if (diag_blk%double_fit) then
475  diag_blk%fit_rv_rfac = 0.3
476  diag_blk%fit_rv_coef = 0.1
477  end if
478 
479  ! Scaling optimization (brute-force)
480  if (all(isnotmsr(diag_blk%fit_rh)).and.all(isnotmsr(diag_blk%fit_rv))) then
481  mse_opt = huge(1.0)
482  alpha_opt = 1.0
483  do isc=1,nsc
484  ! Scaling factor
485  alpha = 0.5+real(isc-1,kind_real)/real(nsc-1,kind_real)*(2.0-0.5)
486 
487  ! Scaled radii
488  fit_rh = alpha*diag_blk%fit_rh
489  fit_rv = alpha*diag_blk%fit_rv
490 
491  ! Define fit
492  if (diag_blk%double_fit) then
493  call fit_diag_dble(mpl,nam%nc3,bpar%nl0r(ib),geom%nl0,bpar%l0rl0b_to_l0(:,:,ib),geom%disth,diag_blk%distv, &
494  & fit_rh,fit_rv,diag_blk%fit_rv_rfac,diag_blk%fit_rv_coef,fit)
495  else
496  call fit_diag(mpl,nam%nc3,bpar%nl0r(ib),geom%nl0,bpar%l0rl0b_to_l0(:,:,ib),geom%disth,diag_blk%distv,fit_rh,fit_rv,fit)
497  end if
498 
499  ! MSE
500  mse = sum((fit-diag_blk%raw)**2,mask=isnotmsr(diag_blk%raw))
501  if (mse<mse_opt) then
502  mse_opt = mse
503  alpha_opt = alpha
504  end if
505  end do
506  diag_blk%fit_rh = alpha_opt*diag_blk%fit_rh
507  diag_blk%fit_rv = alpha_opt*diag_blk%fit_rv
508 
509  if (lprt) then
510  write(mpl%info,'(a)') ''
511  write(mpl%info,'(a13,a,f6.1,a)') '','Scaling optimization, cost function decrease:',abs(mse_opt-mse)/mse*100.0,'%'
512  call flush(mpl%info)
513  end if
514  end if
515 
516  select case (trim(nam%minim_algo))
517  case ('hooke')
518  ! Allocation
519  minim%nx = 0
520  if (nam%lhomh) then
521  minim%nx = minim%nx+1
522  else
523  minim%nx = minim%nx+geom%nl0
524  end if
525  if (nam%lhomv) then
526  minim%nx = minim%nx+1
527  if (diag_blk%double_fit) minim%nx = minim%nx+2
528  else
529  minim%nx = minim%nx+geom%nl0
530  if (diag_blk%double_fit) minim%nx = minim%nx+2*geom%nl0
531  end if
532  minim%ny = nam%nc3*bpar%nl0r(ib)*geom%nl0
533  allocate(minim%x(minim%nx))
534  allocate(minim%guess(minim%nx))
535  allocate(minim%binf(minim%nx))
536  allocate(minim%bsup(minim%nx))
537  allocate(minim%obs(minim%ny))
538  allocate(minim%l0rl0_to_l0(bpar%nl0r(ib),geom%nl0))
539  allocate(minim%disth(nam%nc3))
540  allocate(minim%distv(geom%nl0,geom%nl0))
541 
542  ! Fill minim
543  offset = 0
544  if (nam%lhomh) then
545  minim%guess(offset+1) = diag_blk%fit_rh(1)
546  minim%binf(offset+1) = 0.5*minim%guess(offset+1)
547  minim%bsup(offset+1) = 1.5*minim%guess(offset+1)
548  offset = offset+1
549  else
550  minim%guess(offset+1:offset+geom%nl0) = diag_blk%fit_rh
551  minim%binf(offset+1:offset+geom%nl0) = 0.5*minim%guess(offset+1:offset+geom%nl0)
552  minim%bsup(offset+1:offset+geom%nl0) = 1.5*minim%guess(offset+1:offset+geom%nl0)
553  offset = offset+geom%nl0
554  end if
555  if (nam%lhomv) then
556  minim%guess(offset+1) = diag_blk%fit_rv(1)
557  minim%binf(offset+1) = 0.5*minim%guess(offset+1)
558  minim%bsup(offset+1) = 1.5*minim%guess(offset+1)
559  offset = offset+1
560  if (diag_blk%double_fit) then
561  minim%guess(offset+1) = diag_blk%fit_rv_rfac(1)
562  minim%binf(offset+1) = 0.0
563  minim%bsup(offset+1) = 1.0
564  offset = offset+1
565  minim%guess(offset+1) = diag_blk%fit_rv_coef(1)
566  minim%binf(offset+1) = 0.0
567  minim%bsup(offset+1) = 1.0
568  offset = offset+1
569  end if
570  else
571  minim%guess(offset+1:offset+geom%nl0) = diag_blk%fit_rv
572  minim%binf(offset+1:offset+geom%nl0) = 0.5*minim%guess(offset+1:offset+geom%nl0)
573  minim%bsup(offset+1:offset+geom%nl0) = 1.5*minim%guess(offset+1:offset+geom%nl0)
574  offset = offset+geom%nl0
575  if (diag_blk%double_fit) then
576  minim%guess(offset+1:offset+geom%nl0) = diag_blk%fit_rv_rfac
577  minim%binf(offset+1:offset+geom%nl0) = 0.0
578  minim%bsup(offset+1:offset+geom%nl0) = 1.0
579  offset = offset+geom%nl0
580  minim%guess(offset+1:offset+geom%nl0) = diag_blk%fit_rv_coef
581  minim%binf(offset+1:offset+geom%nl0) = 0.0
582  minim%bsup(offset+1:offset+geom%nl0) = 1.0
583  offset = offset+geom%nl0
584  end if
585  end if
586  minim%obs = pack(diag_blk%raw,mask=.true.)
587  if (diag_blk%double_fit) then
588  minim%cost_function = 'fit_diag_dble'
589  else
590  minim%cost_function = 'fit_diag'
591  end if
592  minim%algo = nam%minim_algo
593  minim%nc3 = nam%nc3
594  minim%nl0r = bpar%nl0r(ib)
595  minim%nl0 = geom%nl0
596  minim%lhomh = nam%lhomh
597  minim%lhomv = nam%lhomv
598  minim%l0rl0_to_l0 = bpar%l0rl0b_to_l0(:,:,ib)
599  minim%disth = geom%disth
600  minim%distv = diag_blk%distv
601 
602  ! Compute fit
603  call minim%compute(mpl,lprt)
604 
605  ! Apply bounds
606  minim%x = max(minim%binf,min(minim%x,minim%bsup))
607 
608  ! Copy parameters
609  offset = 0
610  if (nam%lhomh) then
611  diag_blk%fit_rh = minim%x(offset+1)
612  offset = offset+1
613  else
614  diag_blk%fit_rh = minim%x(offset+1:offset+geom%nl0)
615  offset = offset+geom%nl0
616  end if
617  if (nam%lhomv) then
618  diag_blk%fit_rv = minim%x(offset+1)
619  offset = offset+1
620  if (diag_blk%double_fit) then
621  diag_blk%fit_rv_rfac = minim%x(offset+1)
622  offset = offset+1
623  diag_blk%fit_rv_coef = minim%x(offset+1)
624  offset = offset+1
625  end if
626  else
627  diag_blk%fit_rv = minim%x(offset+1:offset+geom%nl0)
628  offset = offset+geom%nl0
629  if (diag_blk%double_fit) then
630  diag_blk%fit_rv_rfac = minim%x(offset+1:offset+geom%nl0)
631  offset = offset+geom%nl0
632  diag_blk%fit_rv_coef = minim%x(offset+1:offset+geom%nl0)
633  offset = offset+geom%nl0
634  end if
635  end if
636  end select
637 end if
638 
639 ! End associate
640 end associate
641 
642 end subroutine diag_blk_fitting
643 
644 !----------------------------------------------------------------------
645 ! Subroutine: diag_blk_localization
646 ! Purpose: diag_blk localization
647 !----------------------------------------------------------------------
648 subroutine diag_blk_localization(diag_blk,geom,bpar,avg_blk)
650 implicit none
651 
652 ! Passed variables
653 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block (localization)
654 type(geom_type),intent(in) :: geom ! Geometry
655 type(bpar_type),intent(in) :: bpar ! Block parameters
656 type(avg_blk_type),intent(in) :: avg_blk ! Averaged statistics block
657 
658 ! Local variables
659 integer :: il0,jl0r,jc3
660 
661 ! Associate
662 associate(ib=>diag_blk%ib)
663 
664 ! Compute raw localization
665 !$omp parallel do schedule(static) private(il0,jl0r,jc3)
666 do il0=1,geom%nl0
667  do jl0r=1,bpar%nl0r(ib)
668  do jc3=1,bpar%nc3(ib)
669  if (isnotmsr(avg_blk%m11asysq(jc3,jl0r,il0)).and.isnotmsr(avg_blk%m11sq(jc3,jl0r,il0))) &
670  & diag_blk%raw(jc3,jl0r,il0) = avg_blk%m11asysq(jc3,jl0r,il0)/avg_blk%m11sq(jc3,jl0r,il0)
671  end do
672  end do
673 end do
674 
675 ! End associate
676 end associate
677 
678 end subroutine diag_blk_localization
679 
680 !----------------------------------------------------------------------
681 ! Subroutine: diag_blk_hybridization
682 ! Purpose: diag_blk hybridization
683 !----------------------------------------------------------------------
684 subroutine diag_blk_hybridization(diag_blk,geom,bpar,avg_blk,avg_sta_blk)
686 implicit none
687 
688 ! Passed variables
689 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block (localization)
690 type(geom_type),intent(in) :: geom ! Geometry
691 type(bpar_type),intent(in) :: bpar ! Block parameters
692 type(avg_blk_type),intent(in) :: avg_blk ! Averaged statistics block
693 type(avg_blk_type),intent(in) :: avg_sta_blk ! Static averaged statistics block
694 
695 ! Local variables
696 integer :: il0,jl0r,jc3
697 real(kind_real) :: wgt,num,den
698 
699 ! Associate
700 associate(ib=>diag_blk%ib)
701 
702 ! Compute raw hybridization
703 num = 0.0
704 den = 0.0
705 do il0=1,geom%nl0
706  do jl0r=1,bpar%nl0r(ib)
707  do jc3=1,bpar%nc3(ib)
708  if (isnotmsr(avg_blk%m11asysq(jc3,jl0r,il0)).and.isnotmsr(avg_blk%m11sq(jc3,jl0r,il0)) &
709  & .and.isnotmsr(avg_sta_blk%m11sta(jc3,jl0r,il0)).and.isnotmsr(avg_sta_blk%stasq(jc3,jl0r,il0))) then
710  wgt = 1.0 !geom%disth(jc3)*diag_blk%distv(jl0,il0) TODO: define weight
711  num = num+wgt*(1.0-avg_blk%m11asysq(jc3,jl0r,il0)/avg_blk%m11sq(jc3,jl0r,il0)) &
712  & *avg_sta_blk%m11sta(jc3,jl0r,il0)
713  den = den+wgt*(avg_sta_blk%stasq(jc3,jl0r,il0)-avg_sta_blk%m11sta(jc3,jl0r,il0)**2 &
714  & /avg_blk%m11sq(jc3,jl0r,il0))
715  end if
716  end do
717  end do
718 end do
719 if ((num>0.0).and.(den>0.0)) then
720  diag_blk%raw_coef_sta = num/den
721  do il0=1,geom%nl0
722  do jl0r=1,bpar%nl0r(ib)
723  do jc3=1,bpar%nc3(ib)
724  if (isnotmsr(avg_blk%m11asysq(jc3,jl0r,il0)).and.isnotmsr(diag_blk%raw_coef_sta) &
725  & .and.isnotmsr(avg_sta_blk%m11sta(jc3,jl0r,il0)).and.isnotmsr(avg_blk%m11sq(jc3,jl0r,il0))) then
726  ! Compute localization
727  diag_blk%raw(jc3,jl0r,il0) = (avg_blk%m11asysq(jc3,jl0r,il0)-diag_blk%raw_coef_sta &
728  & *avg_sta_blk%m11sta(jc3,jl0r,il0))/avg_blk%m11sq(jc3,jl0r,il0)
729 
730  ! Lower bound
731  if (diag_blk%raw(jc3,jl0r,il0)<0.0) call msr(diag_blk%raw(jc3,jl0r,il0))
732  end if
733  end do
734  end do
735  end do
736 else
737  call msr(diag_blk%raw_coef_sta)
738  call msr(diag_blk%raw)
739 end if
740 
741 ! End associate
742 end associate
743 
744 end subroutine diag_blk_hybridization
745 
746 !----------------------------------------------------------------------
747 ! Subroutine: diag_blk_dualens
748 ! Purpose: diag_blk dualens
749 !----------------------------------------------------------------------
750 subroutine diag_blk_dualens(diag_blk,geom,bpar,avg_blk,avg_lr_blk,diag_lr_blk)
752 implicit none
753 
754 ! Passed variables
755 class(diag_blk_type),intent(inout) :: diag_blk ! Diagnostic block (localization)
756 type(geom_type),intent(in) :: geom ! Geometry
757 type(bpar_type),intent(in) :: bpar ! Block parameters
758 type(avg_blk_type),intent(in) :: avg_blk ! Averaged statistics block
759 type(avg_blk_type),intent(in) :: avg_lr_blk ! LR averaged statistics block
760 type(diag_blk_type),intent(inout) :: diag_lr_blk ! Diagnostic block (LR localization)
761 
762 ! Local variables
763 integer :: il0,jl0r,jc3
764 real(kind_real),allocatable :: num(:),num_lr(:),den(:)
765 
766 ! Associate
767 associate(ib=>diag_blk%ib)
768 
769 ! Allocation
770 allocate(num(bpar%nc3(ib)))
771 allocate(num_lr(bpar%nc3(ib)))
772 allocate(den(bpar%nc3(ib)))
773 
774 ! Compute raw dual-ensemble hybridization
775 do il0=1,geom%nl0
776  do jl0r=1,bpar%nl0r(ib)
777  do jc3=1,bpar%nc3(ib)
778  if (isnotmsr(avg_blk%m11asysq(jc3,jl0r,il0)).and.isnotmsr(avg_blk%m11sq(jc3,jl0r,il0)) &
779  & .and.isnotmsr(avg_lr_blk%m11lrm11asy(jc3,jl0r,il0)).and.isnotmsr(avg_lr_blk%m11lrm11(jc3,jl0r,il0)) &
780  & .and.isnotmsr(avg_lr_blk%m11sq(jc3,jl0r,il0)).and.isnotmsr(avg_lr_blk%m11lrm11asy(jc3,jl0r,il0))) then
781  num(jc3) = avg_blk%m11asysq(jc3,jl0r,il0)*avg_lr_blk%m11sq(jc3,jl0r,il0) &
782  & -avg_lr_blk%m11lrm11asy(jc3,jl0r,il0)*avg_lr_blk%m11lrm11(jc3,jl0r,il0)
783  num_lr(jc3) = avg_lr_blk%m11lrm11asy(jc3,jl0r,il0)*avg_blk%m11sq(jc3,jl0r,il0) &
784  & -avg_blk%m11asysq(jc3,jl0r,il0)*avg_lr_blk%m11lrm11(jc3,jl0r,il0)
785  den(jc3) = avg_blk%m11sq(jc3,jl0r,il0)*avg_lr_blk%m11sq(jc3,jl0r,il0)-avg_lr_blk%m11lrm11(jc3,jl0r,il0)**2
786  if ((num(jc3)>0.0).and.(den(jc3)>0.0)) then
787  diag_blk%raw(jc3,jl0r,il0) = num(jc3)/den(jc3)
788  diag_lr_blk%raw(jc3,jl0r,il0) = num_lr(jc3)/den(jc3)
789  end if
790  end if
791  end do
792  end do
793 end do
794 
795 ! End associate
796 end associate
797 
798 end subroutine diag_blk_dualens
799 
800 end module type_diag_blk
logical function, public sup(x, y)
Definition: tools_repro.F90:85
real(kind_real), parameter maxfactor
subroutine, public fast_fit(mpl, n, iz, dist, raw, fit_r)
Definition: tools_fit.F90:30
integer, parameter, public msvali
Definition: tools_const.F90:23
subroutine diag_blk_localization(diag_blk, geom, bpar, avg_blk)
integer, parameter nsc
real(kind_real), parameter, public msvalr
Definition: tools_const.F90:24
subroutine, public fit_diag_dble(mpl, nc3, nl0r, nl0, l0rl0_to_l0, disth, distv, rh, rv, rv_rfac, rv_coef, fit)
Definition: tools_func.F90:369
subroutine diag_blk_alloc(diag_blk, nam, geom, bpar, samp, ic2a, ib, prefix, double_fit)
subroutine diag_blk_dealloc(diag_blk)
subroutine diag_blk_write(diag_blk, mpl, nam, geom, bpar, filename)
subroutine diag_blk_normalization(diag_blk, geom, bpar, remove_max)
subroutine diag_blk_hybridization(diag_blk, geom, bpar, avg_blk, avg_sta_blk)
subroutine diag_blk_dualens(diag_blk, geom, bpar, avg_blk, avg_lr_blk, diag_lr_blk)
subroutine, public ver_fill(mpl, n, x, profile)
Definition: tools_fit.F90:235
#define max(a, b)
Definition: mosaic_util.h:33
integer, parameter, public kind_real
#define min(a, b)
Definition: mosaic_util.h:32
subroutine diag_blk_fitting(diag_blk, mpl, nam, geom, bpar, samp)
integer, parameter, public ncfloat
Definition: tools_nc.F90:27
subroutine, public fit_diag(mpl, nc3, nl0r, nl0, l0rl0_to_l0, disth, distv, rh, rv, fit)
Definition: tools_func.F90:235