Skip to content

Commit d54abce

Browse files
theresa-corderoTheresa MorrisonTheresa Morrison
authored
Calculate a photoacclimation mixed layer depth in MOM6 (NOAA-GFDL#16)
* Calculate a photoacclimation MLD in MOM6 Using the diagnose MLD routines calculate a MLD that can be used in COBALTv3. * Update interfaces for diagnoseMLD Some previously optional arguments were made nonoptinal in the final version merged into dev/gfdl. So these areguents have been added to the call in MOM_generic_tracers. * Add unset variable in diagnoseMLDbyenergy * Remove timescale variable This parameter seems unneeded at this time. * Change paramter name and though up PR Change "MLD_PHA_FIXED" to "MLD_PHA_CALC" which is default false. Touch up a few formatting issues. Add initialization and comment for mld_pha. * Add fatal errors Add fatal errors if PHA_MLD_CALC is true, but a method is not specified. * Add additional argument to generic tracer stub Add the photo_acc_mld argument to the generic tracer stub in MOM6. --------- Co-authored-by: Theresa Morrison <Theresa.Morrison@gaea57.ncrc.gov> Co-authored-by: Theresa Morrison <Theresa.Morrison@gaea56.ncrc.gov>
1 parent e04b637 commit d54abce

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

config_src/external/GFDL_ocean_BGC/generic_tracer.F90

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ end subroutine generic_tracer_coupler_accumulate
7070
!> Calls the corresponding generic_X_update_from_source routine for each package X
7171
subroutine generic_tracer_source(Temp,Salt,rho_dzt,dzt,hblt_depth,ilb,jlb,tau,dtts,&
7272
grid_dat,model_time,nbands,max_wavelength_band,sw_pen_band,opacity_band,internal_heat,&
73-
frunoff,grid_ht, current_wave_stress, sosga, geolat, eqn_of_state)
73+
frunoff,grid_ht, current_wave_stress, sosga, geolat, eqn_of_state, photo_acc_dpth)
7474
integer, intent(in) :: ilb !< Lower bounds of x extent of input arrays on data domain
7575
integer, intent(in) :: jlb !< Lower bounds of y extent of input arrays on data domain
7676
real, dimension(ilb:,jlb:,:), intent(in) :: Temp !< Potential temperature [deg C]
@@ -98,6 +98,7 @@ subroutine generic_tracer_source(Temp,Salt,rho_dzt,dzt,hblt_depth,ilb,jlb,tau,dt
9898
real, optional , intent(in) :: sosga !< Global average sea surface salinity [ppt]
9999
real, dimension(ilb:,jlb:),optional, intent(in) :: geolat !< Latitude
100100
type(EOS_type), optional, intent(in) :: eqn_of_state !< A pointer to the equation of state
101+
real, dimension(ilb:,jlb:), optional, intent(in) :: photo_acc_dpth
101102
end subroutine generic_tracer_source
102103

103104
!> Update the tracers from bottom fluxes

src/diagnostics/MOM_diagnose_MLD.F90

+10-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module MOM_diagnose_mld
3030
!> Diagnose a mixed layer depth (MLD) determined by a given density difference with the surface.
3131
!> This routine is appropriate in MOM_diabatic_aux due to its position within the time stepping.
3232
subroutine diagnoseMLDbyDensityDifference(id_MLD, h, tv, densityDiff, G, GV, US, diagPtr, &
33-
ref_h_mld, id_ref_z, id_ref_rho, id_N2subML, id_MLDsq, dz_subML)
33+
ref_h_mld, id_ref_z, id_ref_rho, id_N2subML, id_MLDsq, dz_subML, MLD_out)
3434
type(ocean_grid_type), intent(in) :: G !< Grid type
3535
type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
3636
type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
@@ -44,6 +44,8 @@ subroutine diagnoseMLDbyDensityDifference(id_MLD, h, tv, densityDiff, G, GV, US,
4444
real, intent(in) :: ref_h_mld !< Depth of the calculated "surface" densisty [Z ~> m]
4545
integer, intent(in) :: id_ref_z !< Handle (ID) of reference depth diagnostic
4646
integer, intent(in) :: id_ref_rho !< Handle (ID) of reference density diagnostic
47+
real, dimension(SZI_(G),SZJ_(G)), &
48+
optional, intent(inout) :: MLD_out !< Send MLD to other routines [Z ~> m]
4749
integer, optional, intent(in) :: id_N2subML !< Optional handle (ID) of subML stratification
4850
integer, optional, intent(in) :: id_MLDsq !< Optional handle (ID) of squared MLD
4951
real, optional, intent(in) :: dz_subML !< The distance over which to calculate N2subML
@@ -234,11 +236,13 @@ subroutine diagnoseMLDbyDensityDifference(id_MLD, h, tv, densityDiff, G, GV, US,
234236
if ((id_ref_z > 0) .and. (pRef_MLD(is)/=0.)) call post_data(id_ref_z, z_ref_diag , diagPtr)
235237
if (id_ref_rho > 0) call post_data(id_ref_rho, rhoSurf_2d , diagPtr)
236238

239+
if (present(MLD_out)) MLD_out(:,:) = MLD(:,:)
240+
237241
end subroutine diagnoseMLDbyDensityDifference
238242

239243
!> Diagnose a mixed layer depth (MLD) determined by the depth a given energy value would mix.
240244
!> This routine is appropriate in MOM_diabatic_aux due to its position within the time stepping.
241-
subroutine diagnoseMLDbyEnergy(id_MLD, h, tv, G, GV, US, Mixing_Energy, diagPtr)
245+
subroutine diagnoseMLDbyEnergy(id_MLD, h, tv, G, GV, US, Mixing_Energy, diagPtr, MLD_out)
242246
! Author: Brandon Reichl
243247
! Date: October 2, 2020
244248
! //
@@ -270,6 +274,8 @@ subroutine diagnoseMLDbyEnergy(id_MLD, h, tv, G, GV, US, Mixing_Energy, diagPtr)
270274
type(thermo_var_ptrs), intent(in) :: tv !< Structure containing pointers to any
271275
!! available thermodynamic fields.
272276
type(diag_ctrl), pointer :: diagPtr !< Diagnostics structure
277+
real, dimension(SZI_(G),SZJ_(G)), &
278+
optional, intent(inout) :: MLD_out !< Send MLD to other routines [Z ~> m]
273279

274280
! Local variables
275281
real, dimension(SZI_(G),SZJ_(G),3) :: MLD ! Diagnosed mixed layer depth [Z ~> m].
@@ -467,6 +473,8 @@ subroutine diagnoseMLDbyEnergy(id_MLD, h, tv, G, GV, US, Mixing_Energy, diagPtr)
467473
if (id_MLD(2) > 0) call post_data(id_MLD(2), MLD(:,:,2), diagPtr)
468474
if (id_MLD(3) > 0) call post_data(id_MLD(3), MLD(:,:,3), diagPtr)
469475

476+
if (present(MLD_out)) MLD_out(:,:) = MLD(:,:,1)
477+
470478
end subroutine diagnoseMLDbyEnergy
471479

472480
!> \namespace mom_diagnose_mld

src/tracer/MOM_generic_tracer.F90

+64-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ module MOM_generic_tracer
3131

3232
use MOM_ALE_sponge, only : set_up_ALE_sponge_field, ALE_sponge_CS
3333
use MOM_coms, only : EFP_type, max_across_PEs, min_across_PEs, PE_here
34+
use MOM_diagnose_mld, only : diagnoseMLDbyDensityDifference, diagnoseMLDbyEnergy
3435
use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
3536
use MOM_diag_mediator, only : diag_ctrl, get_diag_time_end
3637
use MOM_error_handler, only : MOM_error, FATAL, WARNING, NOTE, is_root_pe
@@ -83,6 +84,14 @@ module MOM_generic_tracer
8384
logical :: tracers_may_reinit !< If true, tracers may go through the
8485
!! initialization code if they are not found in the restart files.
8586

87+
logical :: mld_pha_calc = .False. !< If true, use a fixed value for photoacclimation MLD
88+
real :: mld_pha_val = 0.0 !< The value of fixed photoacclimation MLD
89+
logical :: mld_pha_use_delta_rho = .False. !< If true, use a density diference to find the MLD
90+
real :: mld_pha_href = 0.0 !< The reference depth for density difference based MLD
91+
real :: mld_pha_drho = 0.03 !< The density thershold for a density difference based MLD
92+
logical :: mld_pha_use_delta_eng = .False. !< If true, use an energy diference to find the MLD
93+
real :: mld_pha_deng = 25.0 !< The energy threshold for an energy d ifference based MLD
94+
8695
type(diag_ctrl), pointer :: diag => NULL() !< A structure that is used to
8796
!! regulate the timing of diagnostic output.
8897
type(MOM_restart_CS), pointer :: restart_CSp => NULL() !< Restart control structure
@@ -423,6 +432,42 @@ subroutine initialize_MOM_generic_tracer(restart, day, G, GV, US, h, tv, param_f
423432
enddo
424433
!! end section to re-initialize generic tracers
425434

435+
call get_param(param_file, "MOM", "PHA_MLD_CALC", CS%mld_pha_calc, &
436+
"If false, use a fixed value for the photoacclimation mixed layer depth within the "//&
437+
"generic tracer update. This MLD is only used for photoacclimation. This variable should "//&
438+
"be set to true if using COBALTv3 for the BGC.", default=.false.)
439+
if (CS%mld_pha_calc) then
440+
call get_param(param_file, "MOM", "PHA_MLD_USE_DELTA_RHO", CS%mld_pha_use_delta_rho, &
441+
"If true, use a density difference to find the photoacclimation mixed layer depth "//&
442+
"within the generic tracer update. This MLD is only used for photoacclimation.", default=.false.)
443+
call get_param(param_file, "MOM", "PHA_MLD_USE_DELTA_ENG", CS%mld_pha_use_delta_eng, &
444+
"If true, use an energy difference to find the photoacclimation mixed layer depth "//&
445+
"with the generic tracer update. This MLD is only used for photoacclimation.", default=.false.)
446+
if (CS%mld_pha_use_delta_rho .and. CS%mld_pha_use_delta_eng) then
447+
call MOM_error(FATAL, "PHA_MLD_CALC is set to true and PHA_MLD_USE_DELTA_RHO and PHA_MLD_USE_DELTA_ENG "// &
448+
"are both true. Choose only one option for the calculated photoacclimation MLD!")
449+
elseif ((.not.CS%mld_pha_use_delta_rho) .and. (.not.CS%mld_pha_use_delta_eng)) then
450+
call MOM_error(FATAL, "PHA_MLD_CALC is set to true but PHA_MLD_USE_DELTA_RHO and PHA_MLD_USE_DELTA_ENG "// &
451+
"are both false. Choose an option for the calculated photoacclimation MLD!")
452+
endif
453+
if (CS%mld_pha_use_delta_rho) then
454+
call get_param(param_file, "MOM", "PHA_MLD_HREF", CS%mld_pha_href, &
455+
"The reference depth for a density difference based photoacclimation MLD [m].", &
456+
units='m', default=0.0, scale=US%m_to_Z, do_not_log=.not.CS%mld_pha_use_delta_rho)
457+
call get_param(param_file, "MOM", "PHA_MLD_DRHO", CS%mld_pha_drho, &
458+
"The density difference for a density difference based photoacclimation MLD [kg m-3].", &
459+
units='kg/m3', default=0.03, scale=US%kg_m3_to_R, do_not_log=.not.CS%mld_pha_use_delta_rho)
460+
elseif (CS%mld_pha_use_delta_eng) then
461+
call get_param(param_file, "MOM", "PHA_MLD_DENG", CS%mld_pha_deng, &
462+
"The energy for an energy difference based photoacclimation MLD.", default=25.0, &
463+
units='J/m2',scale=US%W_m2_to_RZ3_T3*US%s_to_T, do_not_log=.not.CS%mld_pha_use_delta_eng)
464+
endif
465+
else
466+
call get_param(param_file, "MOM", "PHA_MLD_VAL", CS%mld_pha_val, &
467+
"The depth of photoacclimation if fixed depth is used [m].", &
468+
units='m', default=0.0, scale=US%m_to_Z)
469+
endif
470+
426471

427472
!Now we can reset the grid mask, axes and time to their true values
428473
!Note that grid_tmask must be set correctly on the data domain boundary
@@ -507,6 +552,8 @@ subroutine MOM_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml,
507552
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: rho_dzt ! Layer mass per unit area [kg m-2]
508553
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: dzt ! Layer vertical extents [m]
509554
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_work ! A work array of thicknesses [H ~> m or kg m-2]
555+
real, dimension(SZI_(G),SZJ_(G)) :: mld_pha ! The mixed layer depth calculated for photoacclimation
556+
! that is used in COBALTv3
510557
integer :: i, j, k, isc, iec, jsc, jec, nk
511558

512559
isc = G%isc ; iec = G%iec ; jsc = G%jsc ; jec = G%jec ; nk = GV%ke
@@ -572,6 +619,17 @@ subroutine MOM_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml,
572619
enddo ; enddo
573620
sosga = global_area_mean(surface_field, G, unscale=US%S_to_ppt)
574621

622+
mld_pha(:,:) = 0.0
623+
if (.not.CS%mld_pha_calc) then
624+
mld_pha(:,:) = CS%mld_pha_val
625+
else
626+
if (CS%mld_pha_use_delta_rho) then
627+
call diagnoseMLDbyDensityDifference(-1, h_old, tv, CS%mld_pha_drho, G, GV, US, CS%diag, CS%mld_pha_href, id_ref_z=-1, id_ref_rho=-1, MLD_out=mld_pha)
628+
elseif (CS%mld_pha_use_delta_eng) then
629+
call diagnoseMLDbyEnergy((/-1, -1, -1/), h_old, tv, G, GV, US, (/CS%mld_pha_deng, CS%mld_pha_deng, CS%mld_pha_deng/), CS%diag, MLD_out=mld_pha)
630+
endif
631+
endif
632+
575633
!
576634
!Calculate tendencies (i.e., field changes at dt) from the sources / sinks
577635
!
@@ -582,7 +640,8 @@ subroutine MOM_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml,
582640
call generic_tracer_source(tv%T, tv%S, rho_dzt, dzt, dz_ml, G%isd, G%jsd, 1, dt, &
583641
G%areaT, get_diag_time_end(CS%diag), &
584642
optics%nbands, optics%max_wavelength_band, optics%sw_pen_band, optics%opacity_band, &
585-
internal_heat=tv%internal_heat, frunoff=fluxes%frunoff, sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state)
643+
internal_heat=tv%internal_heat, frunoff=fluxes%frunoff, sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state, &
644+
photo_acc_dpth=mld_pha)
586645
else
587646
! tv%internal_heat is a null pointer unless DO_GEOTHERMAL = True,
588647
! so we have to check and only do the scaling if it is associated.
@@ -593,14 +652,16 @@ subroutine MOM_generic_tracer_column_physics(h_old, h_new, ea, eb, fluxes, Hml,
593652
sw_pen_band=G%US%QRZ_T_to_W_m2*optics%sw_pen_band(:,:,:), &
594653
opacity_band=G%US%m_to_Z*optics%opacity_band(:,:,:,:), &
595654
internal_heat=G%US%RZ_to_kg_m2*US%C_to_degC*tv%internal_heat(:,:), &
596-
frunoff=G%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state)
655+
frunoff=G%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state, &
656+
photo_acc_dpth=mld_pha*US%Z_to_m)
597657
else
598658
call generic_tracer_source(US%C_to_degC*tv%T, US%S_to_ppt*tv%S, rho_dzt, dzt, dz_ml, G%isd, G%jsd, 1, dt, &
599659
G%US%L_to_m**2*G%areaT(:,:), get_diag_time_end(CS%diag), &
600660
optics%nbands, optics%max_wavelength_band, &
601661
sw_pen_band=G%US%QRZ_T_to_W_m2*optics%sw_pen_band(:,:,:), &
602662
opacity_band=G%US%m_to_Z*optics%opacity_band(:,:,:,:), &
603-
frunoff=G%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state)
663+
frunoff=G%US%RZ_T_to_kg_m2s*fluxes%frunoff(:,:), sosga=sosga, geolat=G%geolatT, eqn_of_state=tv%eqn_of_state, &
664+
photo_acc_dpth=mld_pha*US%Z_to_m)
604665
endif
605666
endif
606667

0 commit comments

Comments
 (0)