Skip to content

Commit 2e2cf36

Browse files
committed
adiabat: add optional mode-2 pass control and skip redundant solves in RCE loop
1 parent b83e0c6 commit 2e2cf36

File tree

5 files changed

+92
-34
lines changed

5 files changed

+92
-34
lines changed

clima/cython/AdiabatClimate.pyx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,15 @@ cdef class AdiabatClimate:
830830
def __set__(self, bint val):
831831
wa_pxd.adiabatclimate_prevent_overconvection_set(self._ptr, &val)
832832

833+
property require_mode2:
834+
"bool. If true, require passing through mode 2 when mode 1 converges before optional mode 3 polishing."
835+
def __get__(self):
836+
cdef bint val
837+
wa_pxd.adiabatclimate_require_mode2_get(self._ptr, &val)
838+
return bool(val)
839+
def __set__(self, bint val):
840+
wa_pxd.adiabatclimate_require_mode2_set(self._ptr, &val)
841+
833842
property rtol:
834843
"float. Relative tolerance of integration."
835844
def __get__(self):

clima/cython/AdiabatClimate_pxd.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ cdef extern void adiabatclimate_convective_max_boundary_shift_set(AdiabatClimate
159159

160160
cdef extern void adiabatclimate_prevent_overconvection_get(AdiabatClimate *ptr, bint *val)
161161
cdef extern void adiabatclimate_prevent_overconvection_set(AdiabatClimate *ptr, bint *val)
162+
cdef extern void adiabatclimate_require_mode2_get(AdiabatClimate *ptr, bint *val)
163+
cdef extern void adiabatclimate_require_mode2_set(AdiabatClimate *ptr, bint *val)
162164

163165
cdef extern void adiabatclimate_rtol_get(AdiabatClimate *ptr, double *val)
164166
cdef extern void adiabatclimate_rtol_set(AdiabatClimate *ptr, double *val)

clima/fortran/AdiabatClimate.f90

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,24 @@ subroutine adiabatclimate_prevent_overconvection_set(ptr, val) bind(c)
996996
c%prevent_overconvection = val
997997
end subroutine
998998

999+
subroutine adiabatclimate_require_mode2_get(ptr, val) bind(c)
1000+
use clima, only: AdiabatClimate
1001+
type(c_ptr), value, intent(in) :: ptr
1002+
logical(c_bool), intent(out) :: val
1003+
type(AdiabatClimate), pointer :: c
1004+
call c_f_pointer(ptr, c)
1005+
val = c%require_mode2
1006+
end subroutine
1007+
1008+
subroutine adiabatclimate_require_mode2_set(ptr, val) bind(c)
1009+
use clima, only: AdiabatClimate
1010+
type(c_ptr), value, intent(in) :: ptr
1011+
logical(c_bool), intent(in) :: val
1012+
type(AdiabatClimate), pointer :: c
1013+
call c_f_pointer(ptr, c)
1014+
c%require_mode2 = val
1015+
end subroutine
1016+
9991017
subroutine adiabatclimate_rtol_get(ptr, val) bind(c)
10001018
use clima, only: AdiabatClimate
10011019
type(c_ptr), value, intent(in) :: ptr

src/adiabat/clima_adiabat.f90

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ module clima_adiabat
120120
integer :: convective_max_boundary_shift = -1
121121
!> If true, shrink convective tops when a strong inversion exists just above.
122122
logical :: prevent_overconvection = .true.
123+
!> If true, require passing through mode 2 when mode 1 converges
124+
!> before optional mode 3 polishing.
125+
logical :: require_mode2 = .false.
123126
!> Per-layer lockout counter used by prevent_overconvection polishing.
124127
!> A positive value temporarily prevents immediate re-demotion of the same
125128
!> convective top boundary to avoid ABAB oscillations.

src/adiabat/clima_adiabat_solve.f90

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ module function AdiabatClimate_RCE(self, P_i_surf, T_surf_guess, T_guess, convec
186186
logical, allocatable :: convecting_with_below_save(:,:)
187187
real(dp), allocatable :: T_in(:), x_init(:), dFdt(:), x_stage(:), x_sol(:), f_sol(:)
188188
integer :: i, j, k, mode_update
189-
logical :: solver_ok, converged1
189+
logical :: solver_ok, perform_solve
190190
logical :: mask_changed
191191

192192
converged = .false.
@@ -226,14 +226,21 @@ module function AdiabatClimate_RCE(self, P_i_surf, T_surf_guess, T_guess, convec
226226
if (allocated(err)) return
227227
endif
228228

229-
converged1 = .false.
229+
perform_solve = .true.
230+
mode_update = 1
231+
if (self%max_rc_iters_convection <= 1) then
232+
mode_update = 2
233+
endif
234+
230235
do i = 1,self%max_rc_iters
231236
j = i
232237

233238
if (self%verbose) then
234239
print"(1x,'Iteration =',i3)", i
235240
endif
236241

242+
if (perform_solve) then
243+
237244
if (allocated(x_init)) deallocate(x_init)
238245
allocate(x_init(size(self%inds_Tx)))
239246
x_init(1) = self%T_surf
@@ -299,55 +306,74 @@ module function AdiabatClimate_RCE(self, P_i_surf, T_surf_guess, T_guess, convec
299306
call AdiabatClimate_objective(self, P_i_surf, x_sol, dFdt, f_sol, err)
300307
if (allocated(err)) return
301308

309+
endif
310+
perform_solve = .true.
311+
302312
! Save the current convective zones
303313
convecting_with_below_save = reshape(convecting_with_below_save,shape=[self%nz,i],pad=self%convecting_with_below)
304314

305-
if (.not.converged1) then
306-
if (i < self%max_rc_iters_convection) then
307-
! permit both convective<->radiative flips
308-
mode_update = 1
309-
else
310-
! permit only radiative->convective growth
311-
mode_update = 2
312-
endif
313-
else
314-
! final polish: trim over-convective tops only
315-
mode_update = 3
316-
endif
317-
318315
call AdiabatClimate_update_convecting_zones(self, P_i_surf, [self%T_surf, self%T], mode_update, err)
319316
if (allocated(err)) return
320317
mask_changed = .not. all(convecting_with_below_save(:,i) .eqv. self%convecting_with_below)
321318

322-
if (.not.converged1) then
319+
! Change modes and check convergence
320+
select case (mode_update)
321+
case (1)
323322
if (.not.mask_changed) then
324-
converged1 = .true.
325-
if (.not.self%prevent_overconvection) then
326-
converged = .true.
327-
else
323+
if (self%require_mode2) then
324+
! We must pass through mode 2
325+
mode_update = 2
326+
perform_solve = .false.
327+
cycle
328+
endif
329+
if (self%prevent_overconvection) then
330+
! We must skip to mode 3
331+
mode_update = 3
332+
perform_solve = .false.
328333
if (self%verbose) then
329334
print'(1x,A)','Preventing overconvection'
330335
endif
331-
! Transition directly into polish once stage-1/2 converges.
332-
call AdiabatClimate_update_convecting_zones(self, P_i_surf, [self%T_surf, self%T], 3, err)
333-
if (allocated(err)) return
334-
mask_changed = .not. all(convecting_with_below_save(:,i) .eqv. self%convecting_with_below)
335-
if (.not.mask_changed) converged = .true.
336+
cycle
337+
endif
338+
! If we get here, then we are converged
339+
converged = .true.
340+
exit
341+
else
342+
! Mask is still changing
343+
if (i >= self%max_rc_iters_convection - 1) then
344+
! We skip to mode 2
345+
mode_update = 2
346+
cycle
336347
endif
337348
endif
338-
else
339-
if (.not.mask_changed) converged = .true.
340-
endif
341-
342-
if (converged) then
343-
if (self%verbose) then
344-
print'(1x,A)','CONVERGED'
349+
case (2)
350+
if (.not.mask_changed) then
351+
if (self%prevent_overconvection) then
352+
! We move on to mode 3
353+
mode_update = 3
354+
perform_solve = .false.
355+
if (self%verbose) then
356+
print'(1x,A)','Preventing overconvection'
357+
endif
358+
cycle
359+
endif
360+
! Otherwise we are converged
361+
converged = .true.
362+
exit
345363
endif
346-
exit
347-
endif
364+
case (3)
365+
if (.not.mask_changed) then
366+
converged = .true.
367+
exit
368+
endif
369+
end select
348370

349371
enddo
350372

373+
if (converged .and. self%verbose) then
374+
print'(1x,A)','CONVERGED'
375+
endif
376+
351377
! Return all information to what is was prior to checking for the root
352378
call AdiabatClimate_set_convecting_zones(self, convecting_with_below_save(:,j), err)
353379
if (allocated(err)) return

0 commit comments

Comments
 (0)