Skip to content

Commit 747c117

Browse files
Merge pull request #794 from NCAR/qceff_inflation_fix
Qceff inflation fix; Explicitly handling BNRHF transform failures.
2 parents 9906662 + 437677f commit 747c117

File tree

5 files changed

+120
-102
lines changed

5 files changed

+120
-102
lines changed

CHANGELOG.rst

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ individual files.
2222

2323
The changes are now listed with the most recent at the top.
2424

25+
**January 30 2025 :: Bug-fix: Explicitly handle BNRHF transform failures. Tag v11.10.1**
26+
27+
- Probit transform failure is caught and an error code is returned
28+
- filter_mod and assim_tools_mod skip variables that fail the transform
29+
2530
**January 23 2025 :: DART_LAB QCEFF. Tag v11.10.0**
2631

2732
- Updated DART_LAB to include QCEFF

assimilation_code/modules/assimilation/assim_tools_mod.f90

+34-15
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
346346
integer(i8), allocatable :: my_state_indx(:)
347347
integer(i8), allocatable :: my_obs_indx(:)
348348

349-
integer :: my_num_obs, i, j, owner, owners_index, my_num_state
349+
integer :: my_num_obs, i, j, owner, owners_index, my_num_state, ierr
350350
integer :: obs_mean_index, obs_var_index
351351
integer :: grp_beg(num_groups), grp_end(num_groups), grp_size, grp_bot, grp_top, group
352352
integer :: num_close_obs, obs_index, num_close_states
@@ -373,6 +373,7 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
373373
type(obs_def_type) :: obs_def
374374
type(time_type) :: obs_time
375375

376+
logical, allocatable :: obs_probit_trans_ok(:), state_probit_trans_ok(:)
376377
logical :: allow_missing_in_state
377378
logical :: local_single_ss_inflate
378379
logical :: local_varying_ss_inflate
@@ -395,13 +396,15 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
395396
my_obs_indx( obs_ens_handle%my_num_vars), &
396397
my_obs_kind( obs_ens_handle%my_num_vars), &
397398
my_obs_type( obs_ens_handle%my_num_vars), &
398-
my_obs_loc( obs_ens_handle%my_num_vars))
399+
my_obs_loc( obs_ens_handle%my_num_vars), &
400+
obs_probit_trans_ok(obs_ens_handle%my_num_vars))
399401

400402
allocate(close_state_dist( ens_handle%my_num_vars), &
401403
close_state_ind( ens_handle%my_num_vars), &
402404
my_state_indx( ens_handle%my_num_vars), &
403405
my_state_kind( ens_handle%my_num_vars), &
404-
my_state_loc( ens_handle%my_num_vars))
406+
my_state_loc( ens_handle%my_num_vars), &
407+
state_probit_trans_ok(ens_handle%my_num_vars))
405408
! end alloc
406409

407410
! Initialize assim_tools_module if needed
@@ -503,8 +506,9 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
503506
! Convert all my state variables to appropriate probit space
504507
call transform_to_probit(ens_size, ens_handle%copies(1:ens_size, i), dist_for_state, &
505508
state_dist_params(i), probit_ens, .false., &
506-
bounded_below, bounded_above, lower_bound, upper_bound)
507-
ens_handle%copies(1:ens_size, i) = probit_ens
509+
bounded_below, bounded_above, lower_bound, upper_bound, ierr)
510+
state_probit_trans_ok(i) = (ierr == 0)
511+
if(state_probit_trans_ok(i)) ens_handle%copies(1:ens_size, i) = probit_ens
508512
end do
509513

510514
!> optionally convert all state location verticals
@@ -541,8 +545,9 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
541545
! Convert all my obs (extended state) variables to appropriate probit space
542546
call transform_to_probit(ens_size, obs_ens_handle%copies(1:ens_size, i), dist_for_obs, &
543547
obs_dist_params(i), probit_ens, .false., &
544-
bounded_below, bounded_above, lower_bound, upper_bound)
545-
obs_ens_handle%copies(1:ens_size, i) = probit_ens
548+
bounded_below, bounded_above, lower_bound, upper_bound, ierr)
549+
obs_probit_trans_ok(i) = (ierr == 0)
550+
if(obs_probit_trans_ok(i)) obs_ens_handle%copies(1:ens_size, i) = probit_ens
546551
endif
547552
end do
548553

@@ -635,9 +640,11 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
635640
orig_obs_prior_var = obs_ens_handle%copies(OBS_PRIOR_VAR_START: &
636641
OBS_PRIOR_VAR_END, owners_index)
637642

638-
! If QC is okay, convert this observation ensemble from probit to regular space
639-
call transform_from_probit(ens_size, obs_ens_handle%copies(1:ens_size, owners_index) , &
640-
obs_dist_params(owners_index), obs_ens_handle%copies(1:ens_size, owners_index))
643+
! Convert this observation ensemble from probit back to regular space if to_probit was successful
644+
if(obs_probit_trans_ok(owners_index)) then
645+
call transform_from_probit(ens_size, obs_ens_handle%copies(1:ens_size, owners_index) , &
646+
obs_dist_params(owners_index), obs_ens_handle%copies(1:ens_size, owners_index))
647+
endif
641648

642649
obs_prior = obs_ens_handle%copies(1:ens_size, owners_index)
643650
endif IF_QC_IS_OKAY
@@ -698,10 +705,14 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
698705
! Convert the prior and posterior for this observation to probit space
699706
call transform_to_probit(grp_size, obs_prior(grp_bot:grp_top), dist_for_obs, &
700707
temp_dist_params, probit_obs_prior(grp_bot:grp_top), .false., &
701-
bounded_below, bounded_above, lower_bound, upper_bound)
708+
bounded_below, bounded_above, lower_bound, upper_bound, ierr)
709+
! If probit transform fails for any group, this observation cannot be assimimlated
710+
if(ierr /= 0) cycle SEQUENTIAL_OBS
702711
call transform_to_probit(grp_size, obs_post(grp_bot:grp_top), dist_for_obs, &
703712
temp_dist_params, probit_obs_post(grp_bot:grp_top), .true., &
704-
bounded_below, bounded_above, lower_bound, upper_bound)
713+
bounded_below, bounded_above, lower_bound, upper_bound, ierr)
714+
! If probit transform fails for any group, this observation cannot be assimimlated
715+
if(ierr /= 0) cycle SEQUENTIAL_OBS
705716
! Free up the storage used for this transform
706717
call deallocate_distribution_params(temp_dist_params)
707718

@@ -761,6 +772,9 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
761772
STATE_UPDATE: do j = 1, num_close_states
762773
state_index = close_state_ind(j)
763774

775+
! If transform to probit failed for this state variable, don't update it
776+
if(.not. state_probit_trans_ok(state_index)) cycle STATE_UPDATE
777+
764778
if ( allow_missing_in_state ) then
765779
! Don't allow update of state ensemble with any missing values
766780
if (any(ens_handle%copies(1:ens_size, state_index) == MISSING_R8)) cycle STATE_UPDATE
@@ -796,6 +810,9 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
796810
OBS_UPDATE: do j = 1, num_close_obs
797811
obs_index = close_obs_ind(j)
798812

813+
! If transform to probit failed for this observed variable, don't update it
814+
if(.not. obs_probit_trans_ok(obs_index)) cycle OBS_UPDATE
815+
799816
! Only have to update obs that have not yet been used
800817
if(my_obs_indx(obs_index) > i) then
801818

@@ -820,7 +837,7 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
820837

821838
! Do the inverse probit transform for state variables
822839
call transform_all_from_probit(ens_size, ens_handle%my_num_vars, ens_handle%copies, &
823-
state_dist_params, ens_handle%copies)
840+
state_dist_params, ens_handle%copies, state_probit_trans_ok)
824841

825842
! Every pe needs to get the current my_inflate and my_inflate_sd back
826843
if(local_single_ss_inflate) then
@@ -876,13 +893,15 @@ subroutine filter_assim(ens_handle, obs_ens_handle, obs_seq, keys, &
876893
my_obs_type, &
877894
close_obs_ind, &
878895
vstatus, &
879-
my_obs_loc)
896+
my_obs_loc, &
897+
state_probit_trans_ok)
880898

881899
deallocate(close_state_dist, &
882900
my_state_indx, &
883901
close_state_ind, &
884902
my_state_kind, &
885-
my_state_loc)
903+
my_state_loc, &
904+
obs_probit_trans_ok)
886905

887906
! end dealloc
888907

assimilation_code/modules/assimilation/filter_mod.f90

+15-11
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,7 @@ subroutine filter_ensemble_inflate(ens_handle, inflate_copy, inflate, ENS_MEAN_C
15671567
real(r8) :: probit_ens(ens_size), probit_ens_mean
15681568
logical :: bounded_below, bounded_above
15691569
real(r8) :: lower_bound, upper_bound
1570-
integer :: dist_type
1570+
integer :: dist_type, ierr
15711571

15721572
! Inflate each group separately; Divide ensemble into num_groups groups
15731573
grp_size = ens_size / num_groups
@@ -1609,16 +1609,20 @@ subroutine filter_ensemble_inflate(ens_handle, inflate_copy, inflate, ENS_MEAN_C
16091609

16101610
call transform_to_probit(grp_size, ens_handle%copies(grp_bot:grp_top, j), &
16111611
dist_type, dist_params, probit_ens(1:grp_size), .false., &
1612-
bounded_below, bounded_above, lower_bound, upper_bound)
1613-
1614-
! Compute the ensemble mean in transformed space
1615-
probit_ens_mean = sum(probit_ens(1:grp_size)) / grp_size
1616-
! Inflate in probit space
1617-
call inflate_ens(inflate, probit_ens(1:grp_size), probit_ens_mean, &
1618-
ens_handle%copies(inflate_copy, j))
1619-
! Transform back from probit space
1620-
call transform_from_probit(grp_size, probit_ens(1:grp_size), &
1621-
dist_params, ens_handle%copies(grp_bot:grp_top, j))
1612+
bounded_below, bounded_above, lower_bound, upper_bound, ierr)
1613+
1614+
! Only inflate if successful return from the probit transform
1615+
if(ierr == 0) then
1616+
! Compute the ensemble mean in transformed space
1617+
probit_ens_mean = sum(probit_ens(1:grp_size)) / grp_size
1618+
! Inflate in probit space
1619+
call inflate_ens(inflate, probit_ens(1:grp_size), probit_ens_mean, &
1620+
ens_handle%copies(inflate_copy, j))
1621+
! Transform back from probit space
1622+
call transform_from_probit(grp_size, probit_ens(1:grp_size), &
1623+
dist_params, ens_handle%copies(grp_bot:grp_top, j))
1624+
endif
1625+
16221626
end do
16231627
endif
16241628
end do

0 commit comments

Comments
 (0)