@@ -197,8 +197,8 @@ module MOM_ice_shelf
197
197
! ! divided by the von Karman constant VK. Was 1/8.
198
198
real :: Vk ! < Von Karman's constant - dimensionless
199
199
real :: Rc ! < critical flux Richardson number.
200
- logical :: buoy_flux_itt_bug ! < If true, fixes buoyancy iteration bug
201
- logical :: salt_flux_itt_bug ! < If true, fixes salt iteration bug
200
+ logical :: buoy_flux_itt_bugfix ! < If true, fixes buoyancy iteration bug
201
+ logical :: salt_flux_itt_bugfix ! < If true, fixes salt iteration bug
202
202
real :: buoy_flux_itt_threshold ! < Buoyancy iteration threshold for convergence
203
203
204
204
! >@{ Diagnostic handles
@@ -298,7 +298,7 @@ subroutine shelf_calc_flux(sfc_state_in, fluxes_in, Time, time_step_in, CS)
298
298
real :: ZETA_N ! < This is the stability constant xi_N = 0.052 from Holland & Jenkins '99
299
299
! ! divided by the von Karman constant VK. Was 1/8. [nondim]
300
300
real :: RC ! < critical flux Richardson number.
301
- real :: I_ZETA_N ! < The inverse of ZETA_N [nondim].
301
+ real :: I_2Zeta_N ! < Half the inverse of Zeta_N [nondim].
302
302
real :: I_LF ! < The inverse of the latent heat of fusion [Q-1 ~> kg J-1].
303
303
real :: I_VK ! < The inverse of the Von Karman constant [nondim].
304
304
real :: PR, SC ! < The Prandtl number and Schmidt number [nondim].
@@ -327,30 +327,38 @@ subroutine shelf_calc_flux(sfc_state_in, fluxes_in, Time, time_step_in, CS)
327
327
real :: dS_ustar ! The difference between the salinity at the ice-ocean interface and the ocean
328
328
! boundary layer salinity times the friction velocity [S Z T-1 ~> ppt m s-1]
329
329
real :: ustar_h ! The friction velocity in the water below the ice shelf [Z T-1 ~> m s-1]
330
- real :: Gam_turb ! [nondim]
330
+ real :: Gam_turb ! A relative turbluent diffusivity [nondim]
331
331
real :: Gam_mol_t, Gam_mol_s ! Relative coefficients of molecular diffusivities [nondim]
332
332
real :: RhoCp ! A typical ocean density times the heat capacity of water [Q R C-1 ~> J m-3 degC-1]
333
- real :: ln_neut
333
+ real :: ln_neut ! The log of the ratio of the neutral boundary layer thickness to the molecular
334
+ ! boundary layer thickness if it is greater than 1 or 0 otherwise [nondim]
334
335
real :: mass_exch ! A mass exchange rate [R Z T-1 ~> kg m-2 s-1]
335
336
real :: Sb_min, Sb_max ! Minimum and maximum boundary salinities [S ~> ppt]
336
337
real :: dS_min, dS_max ! Minimum and maximum salinity changes [S ~> ppt]
337
338
! Variables used in iterating for wB_flux.
338
- real :: wB_flux_new, dDwB_dwB_in
339
- real :: I_Gam_T, I_Gam_S
339
+ real :: wB_flux_next ! The next interation's guess for wB_flux [Z2 T-3 ~> m2 s-2]
340
+ real :: wB_flux_new ! An updated value of wB_flux when Gam_turb is based on wB_flux [Z2 T-3 ~> m2 s-2]
341
+ real :: wB_flux_max ! The upper bound on wB_flux [Z2 T-3 ~> m2 s-2]
342
+ real :: wB_flux_min ! The lower bound on wB_flux [Z2 T-3 ~> m2 s-2]
343
+ real :: dDwB_dwB_in ! The slope of the change in wB_flux between iterations with wB_flux [nondim]
344
+ real :: DwB_max ! The change in wB_flux when it is wB_flux_max [Z2 T-3 ~> m2 s-2]
345
+ real :: DwB_min ! The change in wB_flux when it is wB_flux_min [Z2 T-3 ~> m2 s-2]
346
+ real :: I_Gam_T, I_Gam_S ! Terms that vary inversely with Gam_mol_T or Gam_mol_S and Gam_turb [nondim]
340
347
real :: dG_dwB ! The derivative of Gam_turb with wB [T3 Z-2 ~> s3 m-2]
341
348
real :: taux2, tauy2 ! The squared surface stresses [R2 L2 Z2 T-4 ~> Pa2].
342
349
real :: u2_av, v2_av ! The ice-area weighted average squared ocean velocities [L2 T-2 ~> m2 s-2]
343
- real :: asu1, asu2 ! Ocean areas covered by ice shelves at neighboring u-
344
- real :: asv1, asv2 ! and v-points [L2 ~> m2].
350
+ real :: asu1, asu2 ! Ocean areas covered by ice shelves at neighboring u-points [L2 ~> m2]
351
+ real :: asv1, asv2 ! Ocean areas covered by ice shelves at neighboring v-points [L2 ~> m2]
345
352
real :: I_au, I_av ! The Adcroft reciprocals of the ice shelf areas at adjacent points [L-2 ~> m-2]
346
353
real :: Irho0 ! The inverse of the mean density times a unit conversion factor [R-1 L Z-1 ~> m3 kg-1]
347
354
logical :: Sb_min_set, Sb_max_set
355
+ logical :: root_found
348
356
logical :: update_ice_vel ! If true, it is time to update the ice shelf velocities.
349
357
logical :: coupled_GL ! If true, the grounding line position is determined based on
350
358
! coupled ice-ocean dynamics.
351
359
352
360
real , parameter :: c2_3 = 2.0 / 3.0
353
- character (len= 160 ) :: mesg ! The text of an error message
361
+ character (len= 320 ) :: mesg ! The text of an error message
354
362
integer , dimension (2 ) :: EOSdom ! The i-computational domain for the equation of state
355
363
integer :: i, j, is, ie, js, je, ied, jed, it1, it3
356
364
real :: vaf0, vaf0_A, vaf0_G ! The previous volumes above floatation [Z L2 ~> m3]
@@ -395,7 +403,7 @@ subroutine shelf_calc_flux(sfc_state_in, fluxes_in, Time, time_step_in, CS)
395
403
ZETA_N = CS% Zeta_N
396
404
VK = CS% Vk
397
405
RC = CS% Rc
398
- I_ZETA_N = 1.0 / ZETA_N
406
+ I_2Zeta_N = 0.5 / CS % Zeta_N
399
407
I_LF = 1.0 / CS% Lat_fusion
400
408
SC = CS% kv_molec/ CS% kd_molec_salt
401
409
PR = CS% kv_molec/ CS% kd_molec_temp
@@ -556,68 +564,150 @@ subroutine shelf_calc_flux(sfc_state_in, fluxes_in, Time, time_step_in, CS)
556
564
dT_ustar = (ISS% tfreeze(i,j) - sfc_state% sst(i,j)) * ustar_h
557
565
dS_ustar = (Sbdry(i,j) - sfc_state% sss(i,j)) * ustar_h
558
566
559
- ! First, determine the buoyancy flux assuming no effects of stability
560
- ! on the turbulence. Following H & J '99, this limit also applies
561
- ! when the buoyancy flux is destabilizing.
562
-
563
- if (CS% const_gamma) then ! if using a constant gamma_T
564
- ! note the different form, here I_Gam_T is NOT 1/Gam_T!
567
+ if (CS% const_gamma) then
568
+ ! If using a constant gamma_T, there are no effects of the buoyancy flux on the turbulence.
565
569
I_Gam_T = CS% Gamma_T_3EQ
566
570
I_Gam_S = CS% Gamma_S_3EQ
567
- else
568
- Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0 ))
571
+ wT_flux = dT_ustar * CS% Gamma_T_3EQ
572
+ wB_flux = dB_dS * (dS_ustar * CS% Gamma_S_3EQ) + dB_dT * wT_flux
573
+ else ! gamma_T and gamma_S are a function of the buoyancy flux.
574
+ ! Find the root where wB_flux is consistent with the values of gamma with that flux.
575
+
576
+ ! First, determine the buoyancy flux assuming no effects of stability
577
+ ! on the turbulence. Following H & J '99, this limit also applies
578
+ ! when the buoyancy flux is destabilizing.
579
+ Gam_turb = I_VK * (ln_neut + (I_2Zeta_N - 1.0 ))
569
580
I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb)
570
581
I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb)
571
- endif
582
+ wB_flux = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * (dT_ustar * I_Gam_T)
572
583
573
- wT_flux = dT_ustar * I_Gam_T
574
- wB_flux = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux
584
+ if (wB_flux < 0.0 ) then
585
+ ! The buoyancy flux is stabilizing and will reduce the turbulent
586
+ ! fluxes, and iteration is required.
575
587
576
- if (wB_flux < 0.0 ) then
577
- ! The buoyancy flux is stabilizing and will reduce the turbulent
578
- ! fluxes, and iteration is required.
579
- n_star_term = (ZETA_N * hBL_neut * VK) / (RC * ustar_h** 3 )
580
- do it3 = 1 ,30
581
- ! n_star <= 1.0 is the ratio of working boundary layer thickness
582
- ! to the neutral thickness.
583
- ! hBL = n_star*hBL_neut ; hSub = 1/8*n_star*hBL
588
+ ! n_star <= 1.0 is the ratio of working boundary layer thickness
589
+ ! to the neutral thickness.
590
+ ! hBL = n_star*hBL_neut ; hSub = 1/8*n_star*hBL
591
+ n_star_term = (ZETA_N * hBL_neut * VK) / (RC * ustar_h** 3 )
584
592
585
593
I_n_star = sqrt (1.0 - n_star_term * wB_flux)
586
- dIns_dwB = 0.5 * n_star_term / I_n_star
587
594
if (hBL_neut_h_molec > I_n_star** 2 ) then
588
- Gam_turb = I_VK * ((ln_neut - 2.0 * log (I_n_star)) + &
589
- (0.5 * I_ZETA_N* I_n_star - 1.0 ))
590
- dG_dwB = I_VK * ( - 2.0 / I_n_star + (0.5 * I_ZETA_N)) * dIns_dwB
591
- else
592
- ! The layer dominated by molecular viscosity is smaller than
593
- ! the assumed boundary layer. This should be rare!
594
- Gam_turb = I_VK * (0.5 * I_ZETA_N* I_n_star - 1.0 )
595
- dG_dwB = I_VK * (0.5 * I_ZETA_N) * dIns_dwB
595
+ Gam_turb = I_VK * ((ln_neut - 2.0 * log (I_n_star)) + (I_2Zeta_N* I_n_star - 1.0 ))
596
+ else ! The layer dominated by molecular viscosity is smaller than the boundary layer.
597
+ Gam_turb = I_VK * (I_2Zeta_N* I_n_star - 1.0 )
596
598
endif
597
-
598
- if (CS% const_gamma) then ! if using a constant gamma_T
599
- ! note the different form, here I_Gam_T is NOT 1/Gam_T!
600
- I_Gam_T = CS% Gamma_T_3EQ
601
- I_Gam_S = CS% Gamma_S_3EQ
602
- else
603
- I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb)
604
- I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb)
599
+ I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb)
600
+ I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb)
601
+
602
+ if (CS% buoy_flux_itt_bugfix) then
603
+ wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * (dT_ustar * I_Gam_T)
604
+ root_found = (abs (wB_flux_new - wB_flux) < &
605
+ CS% buoy_flux_itt_threshold* (abs (wB_flux_new) + abs (wB_flux)))
606
+ ! Do not update the flux if its maagnitude would be increased by the otherwise
607
+ ! stabilizing buoyancy fluxes. This can happen when the buoyancy flux
608
+ ! is stabilizing when one of the heat or salt fluxes are destabilizing due
609
+ ! to their different molecular properties.
610
+ if (wB_flux_new <= wB_flux) root_found = .true.
611
+ ! With the line above, the root is always bracketed.
612
+ else ! The bug is never to update the buoyancy flux.
613
+ root_found = .true.
605
614
endif
606
615
607
- wT_flux = dT_ustar * I_Gam_T
608
- wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux
616
+ if (.not. root_found) then
617
+ wB_flux_max = 0.0 ; DwB_max = wB_flux
618
+ wB_flux_min = wB_flux ; DwB_min = wB_flux_new - wB_flux
619
+ ! The test about 10 lines above ensures that that (DwB_max <= 0) and (DwB_min >= 0),
620
+
621
+ if (wB_flux_min* n_star_term <= (1.0 - hBL_neut_h_molec)) then
622
+ ! The solution is in the limit where abs(wB_flux) is small and
623
+ ! Gam_turb = I_VK * ((ln_neut - 2.0*log(I_n_star)) + (I_2Zeta_N*I_n_star - 1.0))
624
+ elseif (wB_flux_max* n_star_term >= (1.0 - hBL_neut_h_molec)) then
625
+ ! The solution is in the limit where abs(wB_flux) is large and
626
+ ! Gam_turb = I_VK * (I_2Zeta_N*I_n_star - 1.0)
627
+ else
628
+ ! The derivative of Gam_turb with wB_flux has a discontinuous change within the
629
+ ! bracketed range of values. For a first guess, take this discontinous slope
630
+ ! value, as Newton's method and the false position method do not converge well
631
+ ! when this discontinuity is between a guess and the solution.
632
+
633
+ ! Set wB_flux so that I_n_star**2 = hBL_neut_h_molec
634
+ ! I_n_star = sqrt(1.0 - n_star_term * wB_flux)
635
+ wB_flux = (1.0 - hBL_neut_h_molec) / n_star_term
636
+ I_n_star = sqrt (hBL_neut_h_molec)
637
+ Gam_turb = I_VK * (I_2Zeta_N* I_n_star - 1.0 )
638
+ I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb)
639
+ I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb)
640
+
641
+ wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * (dT_ustar * I_Gam_T)
642
+ if (abs (wB_flux_new - wB_flux) <= CS% buoy_flux_itt_threshold* (abs (wB_flux_new) + abs (wB_flux))) then
643
+ ! The root has been found to within the tolerance at the kink. This should be very rare.
644
+ root_found = .true.
645
+ elseif (wB_flux_new > wB_flux) then
646
+ ! The solution is in the limit where abs(wB_flux) is small and
647
+ ! Gam_turb = I_VK * ((ln_neut - 2.0*log(I_n_star)) + (I_2Zeta_N*I_n_star - 1.0))
648
+ wB_flux_min = wB_flux ; DwB_min = wB_flux_new - wB_flux
649
+ else
650
+ ! The solution is in the limt where abs(wB_flux) is large and
651
+ ! Gam_turb = I_VK * (I_2Zeta_N*I_n_star - 1.0)
652
+ wB_flux_max = wB_flux ; DwB_max = wB_flux_new - wB_flux
653
+ endif
654
+ endif
655
+ endif
609
656
610
- ! Find the root where wB_flux_new = wB_flux.
611
- if (abs (wB_flux_new - wB_flux) < CS% buoy_flux_itt_threshold* (abs (wB_flux_new) + abs (wB_flux))) exit
657
+ if (.not. root_found) then
658
+ ! Use the false position for the next guess.
659
+ wB_flux = wB_flux_min + (wB_flux_max- wB_flux_min) * (DwB_min / (DwB_min - DwB_max))
660
+
661
+ do it3 = 1 ,30
662
+ ! Iterate using Newton's method with bounds or the false position method to find the root.
663
+
664
+ I_n_star = sqrt (1.0 - n_star_term * wB_flux)
665
+ dIns_dwB = - 0.5 * n_star_term / I_n_star
666
+ if (hBL_neut_h_molec > I_n_star** 2 ) then
667
+ Gam_turb = I_VK * ((ln_neut - 2.0 * log (I_n_star)) + (I_2Zeta_N* I_n_star - 1.0 ))
668
+ dG_dwB = I_VK * (( - 2.0 / I_n_star + I_2Zeta_N) * dIns_dwB)
669
+ else
670
+ ! The layer dominated by molecular viscosity is smaller than the boundary layer.
671
+ Gam_turb = I_VK * (I_2Zeta_N* I_n_star - 1.0 )
672
+ dG_dwB = I_VK * (I_2Zeta_N * dIns_dwB)
673
+ endif
674
+ I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb)
675
+ I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb)
676
+ wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * (dT_ustar * I_Gam_T)
677
+
678
+ ! Test for convergence to within tolerance at the point where wB_flux_new = wB_flux.
679
+ if (abs (wB_flux_new - wB_flux) <= CS% buoy_flux_itt_threshold* (abs (wB_flux_new) + abs (wB_flux))) &
680
+ root_found = .true.
681
+ if (root_found) exit
682
+
683
+ dDwB_dwB_in = - dG_dwB * (dB_dS * (dS_ustar * I_Gam_S** 2 ) + &
684
+ dB_dT * (dT_ustar * I_Gam_T** 2 )) - 1.0
685
+ if ((dDwB_dwB_in >= 0.0 ) .or. &
686
+ ( wB_flux - wB_flux_new >= abs (dDwB_dwB_in)* (wB_flux_max - wB_flux)) .or. &
687
+ ( wB_flux - wB_flux_new <= abs (dDwB_dwB_in)* (wB_flux_min - wB_flux)) ) then
688
+ ! Use the False position method to determine the guess for the next iteration when
689
+ ! Newton's method would go out of bounds
690
+ wB_flux_next = wB_flux_min + (wB_flux_max- wB_flux_min) * (DwB_min / (DwB_min - DwB_max))
691
+ else
692
+ ! Use Newton's method for the next guess.
693
+ wB_flux_next = wB_flux - (wB_flux_new - wB_flux) / dDwB_dwB_in
694
+ endif
695
+
696
+ ! Reset one of the bounds inward.
697
+ if (wB_flux_new - wB_flux > 0 ) then
698
+ wB_flux_min = wB_flux ; DwB_min = wB_flux_new - wB_flux
699
+ else
700
+ wB_flux_max = wB_flux ; DwB_max = wB_flux_new - wB_flux
701
+ endif
702
+
703
+ ! Update wB_flux
704
+ wB_flux = wB_flux_next
705
+ enddo ! it3
706
+ endif
612
707
613
- dDwB_dwB_in = dG_dwB * (dB_dS * (dS_ustar * I_Gam_S** 2 ) + &
614
- dB_dT * (dT_ustar * I_Gam_T** 2 )) - 1.0
615
- ! This is Newton's method without any bounds. Should bounds be needed?
616
- wB_flux_new = wB_flux - (wB_flux_new - wB_flux) / dDwB_dwB_in
617
- ! Update wB_flux
618
- if (CS% buoy_flux_itt_bug) wB_flux = wB_flux_new
619
- enddo ! it3
620
- endif
708
+ endif ! End of test for first guess of wB_flux < 0.
709
+ wT_flux = dT_ustar * I_Gam_T
710
+ endif ! End of test for CS%const_gamma
621
711
622
712
ISS% tflux_ocn(i,j) = RhoCp * wT_flux
623
713
exch_vel_t(i,j) = ustar_h * I_Gam_T
@@ -688,7 +778,7 @@ subroutine shelf_calc_flux(sfc_state_in, fluxes_in, Time, time_step_in, CS)
688
778
Sbdry(i,j) = Sbdry_it
689
779
endif ! Sb_min_set
690
780
691
- if (.not. CS% salt_flux_itt_bug ) Sbdry(i,j) = Sbdry_it
781
+ if (.not. CS% salt_flux_itt_bugfix ) Sbdry(i,j) = Sbdry_it
692
782
693
783
endif ! CS%find_salt_root
694
784
@@ -1686,10 +1776,10 @@ subroutine initialize_ice_shelf(param_file, ocn_grid, Time, CS, diag, Time_init,
1686
1776
call get_param(param_file, mdl, " ICE_SHELF_RC" , CS% Rc, &
1687
1777
" Critical flux Richardson number for ice melt " , &
1688
1778
units= " nondim" , default= 0.20 )
1689
- call get_param(param_file, mdl, " ICE_SHELF_BUOYANCY_FLUX_ITT_BUG " , CS% buoy_flux_itt_bug , &
1690
- " Bug fix of buoyancy iteration" , default= .true. )
1691
- call get_param(param_file, mdl, " ICE_SHELF_SALT_FLUX_ITT_BUG " , CS% salt_flux_itt_bug , &
1692
- " Bug fix of salt iteration" , default= .true. )
1779
+ call get_param(param_file, mdl, " ICE_SHELF_BUOYANCY_FLUX_ITT_BUGFIX " , CS% buoy_flux_itt_bugfix , &
1780
+ " Bug fix of buoyancy iteration" , default= .true. , old_name = " ICE_SHELF_BUOYANCY_FLUX_ITT_BUG " )
1781
+ call get_param(param_file, mdl, " ICE_SHELF_SALT_FLUX_ITT_BUGFIX " , CS% salt_flux_itt_bugfix , &
1782
+ " Bug fix of salt iteration" , default= .true. , old_name = " ICE_SHELF_SALT_FLUX_ITT_BUG " )
1693
1783
call get_param(param_file, mdl, " ICE_SHELF_BUOYANCY_FLUX_ITT_THRESHOLD" , CS% buoy_flux_itt_threshold, &
1694
1784
" Convergence criterion of Newton's method for ice shelf " // &
1695
1785
" buoyancy iteration." , units= " nondim" , default= 1.0e-4 )
0 commit comments