From c56f8e702a49f8e77dd24b0bbe28e71129cbbaf5 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 Aug 2020 16:09:29 -0600 Subject: [PATCH 01/47] new snow tracer implementation (no physics) --- columnphysics/icepack_parameters.F90 | 86 +++++++++++++++- columnphysics/icepack_tracers.F90 | 38 ++++++- configuration/driver/icedrv_domain_size.F90 | 1 + configuration/driver/icedrv_init.F90 | 108 +++++++++++++++++--- configuration/driver/icedrv_restart.F90 | 74 +++++++++++++- configuration/scripts/icepack.build | 2 +- configuration/scripts/icepack.settings | 1 + configuration/scripts/icepack_in | 12 +++ 8 files changed, 298 insertions(+), 24 deletions(-) diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index b3c0f1347..972894e6b 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -308,6 +308,24 @@ module icepack_parameters real (kind=dbl_kind), public :: & hp1 = 0.01_dbl_kind ! critical pond lid thickness for topo ponds +!----------------------------------------------------------------------- +! Parameters for snow redistribution, metamorphosis +!----------------------------------------------------------------------- + + character (len=char_len), public :: & + snwredist = 'none' ! type of snow redistribution + + logical (kind=log_kind), public :: & + use_smliq_pnd = .false. ! use liquid in snow for ponds + + real (kind=dbl_kind), public :: & + rsnw_fall = 54.526_dbl_kind, & ! radius of new snow (10^-6 m) + rsnw_tmax = 1500.0_dbl_kind, & ! maximum snow radius (10^-6 m) + rhosnew = 100.0_dbl_kind, & ! new snow density (kg/m^3) + rhosmax = 450.0_dbl_kind, & ! maximum snow density (kg/m^3) + windmin = 10.0_dbl_kind, & ! minimum wind speed to compact snow (m/s) + drhosdwind = 27.3_dbl_kind ! wind compaction factor (kg s/m^4) + !----------------------------------------------------------------------- ! Parameters for biogeochemistry !----------------------------------------------------------------------- @@ -413,7 +431,9 @@ subroutine icepack_init_parameters( & fr_dFe_in, k_nitrif_in, t_iron_conv_in, max_loss_in, & max_dfe_doc1_in, fr_resp_s_in, conserv_check_in, & y_sk_DMS_in, t_sk_conv_in, t_sk_ox_in, frazil_scav_in, & - sw_redist_in, sw_frac_in, sw_dtemp_in) + sw_redist_in, sw_frac_in, sw_dtemp_in, & + snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & + rhosnew_in, rhosmax_in, windmin_in, drhosdwind_in) !----------------------------------------------------------------- ! parameter constants @@ -707,6 +727,24 @@ subroutine icepack_init_parameters( & real (kind=dbl_kind), intent(in), optional :: & hp1_in ! critical parameter for pond ice thickness +!----------------------------------------------------------------------- +! Parameters for snow redistribution, metamorphosis +!----------------------------------------------------------------------- + + character (len=char_len), intent(in), optional :: & + snwredist_in ! type of snow redistribution + + logical (kind=log_kind), intent(in), optional :: & + use_smliq_pnd_in ! use liquid in snow for ponds + + real (kind=dbl_kind), intent(in), optional :: & + rsnw_fall_in, & ! radius of new snow (10^-6 m) + rsnw_tmax_in, & ! maximum snow radius (10^-6 m) + rhosnew_in, & ! new snow density (kg/m^3) + rhosmax_in, & ! maximum snow density (kg/m^3) + windmin_in, & ! minimum wind speed to compact snow (m/s) + drhosdwind_in ! wind compaction factor (kg s/m^4) + !autodocument_end character(len=*),parameter :: subname='(icepack_init_parameters)' @@ -820,6 +858,14 @@ subroutine icepack_init_parameters( & if (present(pndaspect_in) ) pndaspect = pndaspect_in if (present(hs1_in) ) hs1 = hs1_in if (present(hp1_in) ) hp1 = hp1_in + if (present(snwredist_in) ) snwredist = snwredist_in + if (present(use_smliq_pnd_in) ) use_smliq_pnd = use_smliq_pnd_in + if (present(rsnw_fall_in) ) rsnw_fall = rsnw_fall_in + if (present(rsnw_tmax_in) ) rsnw_tmax = rsnw_tmax_in + if (present(rhosnew_in) ) rhosnew = rhosnew_in + if (present(rhosmax_in) ) rhosmax = rhosmax_in + if (present(windmin_in) ) windmin = windmin_in + if (present(drhosdwind_in) ) drhosdwind = drhosdwind_in if (present(bgc_flux_type_in) ) bgc_flux_type = bgc_flux_type_in if (present(z_tracers_in) ) z_tracers = z_tracers_in if (present(scale_bgc_in) ) scale_bgc = scale_bgc_in @@ -911,7 +957,9 @@ subroutine icepack_query_parameters( & fr_mort2min_out, fr_resp_s_out, fr_dFe_out, & k_nitrif_out, t_iron_conv_out, max_loss_out, max_dfe_doc1_out, & y_sk_DMS_out, t_sk_conv_out, t_sk_ox_out, frazil_scav_out, & - sw_redist_out, sw_frac_out, sw_dtemp_out) + sw_redist_out, sw_frac_out, sw_dtemp_out, & + snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & + rhosnew_out, rhosmax_out, windmin_out, drhosdwind_out) !----------------------------------------------------------------- ! parameter constants @@ -1214,6 +1262,24 @@ subroutine icepack_query_parameters( & real (kind=dbl_kind), intent(out), optional :: & hp1_out ! critical parameter for pond ice thickness +!----------------------------------------------------------------------- +! Parameters for snow redistribution, metamorphosis +!----------------------------------------------------------------------- + + character (len=char_len), intent(out), optional :: & + snwredist_out ! type of snow redistribution + + logical (kind=log_kind), intent(out), optional :: & + use_smliq_pnd_out ! use liquid in snow for ponds + + real (kind=dbl_kind), intent(out), optional :: & + rsnw_fall_out, & ! radius of new snow (10^-6 m) + rsnw_tmax_out, & ! maximum snow radius (10^-6 m) + rhosnew_out, & ! new snow density (kg/m^3) + rhosmax_out, & ! maximum snow density (kg/m^3) + windmin_out, & ! minimum wind speed to compact snow (m/s) + drhosdwind_out ! wind compaction factor (kg s/m^4) + !autodocument_end character(len=*),parameter :: subname='(icepack_query_parameters)' @@ -1368,6 +1434,14 @@ subroutine icepack_query_parameters( & if (present(pndaspect_out) ) pndaspect_out = pndaspect if (present(hs1_out) ) hs1_out = hs1 if (present(hp1_out) ) hp1_out = hp1 + if (present(snwredist_out) ) snwredist_out = snwredist + if (present(use_smliq_pnd_out) ) use_smliq_pnd_out= use_smliq_pnd + if (present(rsnw_fall_out) ) rsnw_fall_out = rsnw_fall + if (present(rsnw_tmax_out) ) rsnw_tmax_out = rsnw_tmax + if (present(rhosnew_out) ) rhosnew_out = rhosnew + if (present(rhosmax_out) ) rhosmax_out = rhosmax + if (present(windmin_out) ) windmin_out = windmin + if (present(drhosdwind_out) ) drhosdwind_out = drhosdwind if (present(bgc_flux_type_out) ) bgc_flux_type_out= bgc_flux_type if (present(z_tracers_out) ) z_tracers_out = z_tracers if (present(scale_bgc_out) ) scale_bgc_out = scale_bgc @@ -1546,6 +1620,14 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " pndaspect = ", pndaspect write(iounit,*) " hs1 = ", hs1 write(iounit,*) " hp1 = ", hp1 + write(iounit,*) " snwredist = ", snwredist + write(iounit,*) " use_smliq_pnd = ", use_smliq_pnd + write(iounit,*) " rsnw_fall = ", rsnw_fall + write(iounit,*) " rsnw_tmax = ", rsnw_tmax + write(iounit,*) " rhosnew = ", rhosnew + write(iounit,*) " rhosmax = ", rhosmax + write(iounit,*) " windmin = ", windmin + write(iounit,*) " drhosdwind = ", drhosdwind write(iounit,*) " bgc_flux_type = ", bgc_flux_type write(iounit,*) " z_tracers = ", z_tracers write(iounit,*) " scale_bgc = ", scale_bgc diff --git a/columnphysics/icepack_tracers.F90 b/columnphysics/icepack_tracers.F90 index 6a72498a7..05ffde9b7 100644 --- a/columnphysics/icepack_tracers.F90 +++ b/columnphysics/icepack_tracers.F90 @@ -80,6 +80,10 @@ module icepack_tracers nt_hpnd = 0, & ! melt pond depth nt_ipnd = 0, & ! melt pond refrozen lid thickness nt_fsd = 0, & ! floe size distribution + nt_smice = 0, & ! mass of ice in snow + nt_smliq = 0, & ! mass of liquid water in snow + nt_rhos = 0, & ! snow density + nt_rsnw = 0, & ! snow grain radius nt_isosno = 0, & ! starting index for isotopes in snow nt_isoice = 0, & ! starting index for isotopes in ice nt_aero = 0, & ! starting index for aerosols in ice @@ -102,6 +106,7 @@ module icepack_tracers tr_pond_cesm = .false., & ! if .true., use cesm pond tracer tr_pond_lvl = .false., & ! if .true., use level-ice pond tracer tr_pond_topo = .false., & ! if .true., use explicit topography-based ponds + tr_snow = .false., & ! if .true., use snow metamorphosis tracers tr_iso = .false., & ! if .true., use isotope tracers tr_aero = .false., & ! if .true., use aerosol tracers tr_brine = .false., & ! if .true., brine height differs from ice thickness @@ -201,7 +206,7 @@ module icepack_tracers ! set tracer active flags subroutine icepack_init_tracer_flags(& - tr_iage_in, tr_FY_in, tr_lvl_in, & + tr_iage_in, tr_FY_in, tr_lvl_in, tr_snow_in, & tr_pond_in, tr_pond_cesm_in, tr_pond_lvl_in, tr_pond_topo_in, & tr_fsd_in, tr_aero_in, tr_iso_in, tr_brine_in, tr_zaero_in, & tr_bgc_Nit_in, tr_bgc_N_in, tr_bgc_DON_in, tr_bgc_C_in, tr_bgc_chl_in, & @@ -216,6 +221,7 @@ subroutine icepack_init_tracer_flags(& tr_pond_cesm_in , & ! if .true., use cesm pond tracer tr_pond_lvl_in , & ! if .true., use level-ice pond tracer tr_pond_topo_in , & ! if .true., use explicit topography-based ponds + tr_snow_in , & ! if .true., use snow metamorphosis tracers tr_fsd_in , & ! if .true., use floe size distribution tracers tr_iso_in , & ! if .true., use isotope tracers tr_aero_in , & ! if .true., use aerosol tracers @@ -244,6 +250,7 @@ subroutine icepack_init_tracer_flags(& if (present(tr_pond_cesm_in)) tr_pond_cesm = tr_pond_cesm_in if (present(tr_pond_lvl_in) ) tr_pond_lvl = tr_pond_lvl_in if (present(tr_pond_topo_in)) tr_pond_topo = tr_pond_topo_in + if (present(tr_snow_in) ) tr_snow = tr_snow_in if (present(tr_fsd_in) ) tr_fsd = tr_fsd_in if (present(tr_iso_in) ) tr_iso = tr_iso_in if (present(tr_aero_in) ) tr_aero = tr_aero_in @@ -268,7 +275,7 @@ end subroutine icepack_init_tracer_flags ! query tracer active flags subroutine icepack_query_tracer_flags(& - tr_iage_out, tr_FY_out, tr_lvl_out, & + tr_iage_out, tr_FY_out, tr_lvl_out, tr_snow_out, & tr_pond_out, tr_pond_cesm_out, tr_pond_lvl_out, tr_pond_topo_out, & tr_fsd_out, tr_aero_out, tr_iso_out, tr_brine_out, tr_zaero_out, & tr_bgc_Nit_out, tr_bgc_N_out, tr_bgc_DON_out, tr_bgc_C_out, tr_bgc_chl_out, & @@ -283,6 +290,7 @@ subroutine icepack_query_tracer_flags(& tr_pond_cesm_out , & ! if .true., use cesm pond tracer tr_pond_lvl_out , & ! if .true., use level-ice pond tracer tr_pond_topo_out , & ! if .true., use explicit topography-based ponds + tr_snow_out , & ! if .true., use snow metamorphosis tracers tr_fsd_out , & ! if .true., use floe size distribution tr_iso_out , & ! if .true., use isotope tracers tr_aero_out , & ! if .true., use aerosol tracers @@ -311,6 +319,7 @@ subroutine icepack_query_tracer_flags(& if (present(tr_pond_cesm_out)) tr_pond_cesm_out = tr_pond_cesm if (present(tr_pond_lvl_out) ) tr_pond_lvl_out = tr_pond_lvl if (present(tr_pond_topo_out)) tr_pond_topo_out = tr_pond_topo + if (present(tr_snow_out) ) tr_snow_out = tr_snow if (present(tr_fsd_out) ) tr_fsd_out = tr_fsd if (present(tr_iso_out) ) tr_iso_out = tr_iso if (present(tr_aero_out) ) tr_aero_out = tr_aero @@ -350,6 +359,7 @@ subroutine icepack_write_tracer_flags(iounit) write(iounit,*) " tr_pond_cesm = ",tr_pond_cesm write(iounit,*) " tr_pond_lvl = ",tr_pond_lvl write(iounit,*) " tr_pond_topo = ",tr_pond_topo + write(iounit,*) " tr_snow = ",tr_snow write(iounit,*) " tr_fsd = ",tr_fsd write(iounit,*) " tr_iso = ",tr_iso write(iounit,*) " tr_aero = ",tr_aero @@ -377,6 +387,7 @@ subroutine icepack_init_tracer_indices(& nt_Tsfc_in, nt_qice_in, nt_qsno_in, nt_sice_in, & nt_fbri_in, nt_iage_in, nt_FY_in, & nt_alvl_in, nt_vlvl_in, nt_apnd_in, nt_hpnd_in, nt_ipnd_in, & + nt_smice_in, nt_smliq_in, nt_rhos_in, nt_rsnw_in, & nt_fsd_in, nt_isosno_in, nt_isoice_in, & nt_aero_in, nt_zaero_in, nt_bgc_C_in, & nt_bgc_N_in, nt_bgc_chl_in, nt_bgc_DOC_in, nt_bgc_DON_in, & @@ -397,12 +408,16 @@ subroutine icepack_init_tracer_indices(& nt_sice_in, & ! volume-weighted ice bulk salinity (CICE grid layers) nt_fbri_in, & ! volume fraction of ice with dynamic salt (hinS/vicen*aicen) nt_iage_in, & ! volume-weighted ice age - nt_FY_in, & ! area-weighted first-year ice area + nt_FY_in, & ! area-weighted first-year ice area nt_alvl_in, & ! level ice area fraction nt_vlvl_in, & ! level ice volume fraction nt_apnd_in, & ! melt pond area fraction nt_hpnd_in, & ! melt pond depth nt_ipnd_in, & ! melt pond refrozen lid thickness + nt_smice_in,& ! mass of ice in snow + nt_smliq_in,& ! mass of liquid water in snow + nt_rhos_in, & ! snow density + nt_rsnw_in, & ! snow grain radius nt_fsd_in, & ! floe size distribution nt_isosno_in, & ! starting index for isotopes in snow nt_isoice_in, & ! starting index for isotopes in ice @@ -481,6 +496,10 @@ subroutine icepack_init_tracer_indices(& if (present(nt_hpnd_in)) nt_hpnd = nt_hpnd_in if (present(nt_ipnd_in)) nt_ipnd = nt_ipnd_in if (present(nt_fsd_in) ) nt_fsd = nt_fsd_in + if (present(nt_smice_in) ) nt_smice = nt_smice_in + if (present(nt_smliq_in) ) nt_smliq = nt_smliq_in + if (present(nt_rhos_in) ) nt_rhos = nt_rhos_in + if (present(nt_rsnw_in) ) nt_rsnw = nt_rsnw_in if (present(nt_isosno_in) ) nt_isosno = nt_isosno_in if (present(nt_isoice_in) ) nt_isoice = nt_isoice_in if (present(nt_aero_in) ) nt_aero = nt_aero_in @@ -730,6 +749,7 @@ subroutine icepack_query_tracer_indices(& nt_Tsfc_out, nt_qice_out, nt_qsno_out, nt_sice_out, & nt_fbri_out, nt_iage_out, nt_FY_out, & nt_alvl_out, nt_vlvl_out, nt_apnd_out, nt_hpnd_out, nt_ipnd_out, & + nt_smice_out, nt_smliq_out, nt_rhos_out, nt_rsnw_out, & nt_fsd_out, nt_isosno_out, nt_isoice_out, & nt_aero_out, nt_zaero_out, nt_bgc_C_out, & nt_bgc_N_out, nt_bgc_chl_out, nt_bgc_DOC_out, nt_bgc_DON_out, & @@ -756,6 +776,10 @@ subroutine icepack_query_tracer_indices(& nt_apnd_out, & ! melt pond area fraction nt_hpnd_out, & ! melt pond depth nt_ipnd_out, & ! melt pond refrozen lid thickness + nt_smice_out,& ! mass of ice in snow + nt_smliq_out,& ! mass of liquid water in snow + nt_rhos_out, & ! snow density + nt_rsnw_out, & ! snow grain radius nt_fsd_out, & ! floe size distribution nt_isosno_out, & ! starting index for isotopes in snow nt_isoice_out, & ! starting index for isotopes in ice @@ -832,6 +856,10 @@ subroutine icepack_query_tracer_indices(& if (present(nt_hpnd_out)) nt_hpnd_out = nt_hpnd if (present(nt_ipnd_out)) nt_ipnd_out = nt_ipnd if (present(nt_fsd_out) ) nt_fsd_out = nt_fsd + if (present(nt_smice_out) ) nt_smice_out = nt_smice + if (present(nt_smliq_out) ) nt_smliq_out = nt_smliq + if (present(nt_rhos_out) ) nt_rhos_out = nt_rhos + if (present(nt_rsnw_out) ) nt_rsnw_out = nt_rsnw if (present(nt_isosno_out) ) nt_isosno_out = nt_isosno if (present(nt_isoice_out) ) nt_isoice_out = nt_isoice if (present(nt_aero_out) ) nt_aero_out = nt_aero @@ -907,6 +935,10 @@ subroutine icepack_write_tracer_indices(iounit) write(iounit,*) " nt_hpnd = ",nt_hpnd write(iounit,*) " nt_ipnd = ",nt_ipnd write(iounit,*) " nt_fsd = ",nt_fsd + write(iounit,*) " nt_smice = ",nt_smice + write(iounit,*) " nt_smliq = ",nt_smliq + write(iounit,*) " nt_rhos = ",nt_rhos + write(iounit,*) " nt_rsnw = ",nt_rsnw write(iounit,*) " nt_isosno = ",nt_isosno write(iounit,*) " nt_isoice = ",nt_isoice write(iounit,*) " nt_aero = ",nt_aero diff --git a/configuration/driver/icedrv_domain_size.F90 b/configuration/driver/icedrv_domain_size.F90 index 6444c9af5..31b6c734a 100644 --- a/configuration/driver/icedrv_domain_size.F90 +++ b/configuration/driver/icedrv_domain_size.F90 @@ -48,6 +48,7 @@ module icedrv_domain_size + TRFY & ! first-year area + TRLVL*2 & ! level/deformed ice + TRPND*3 & ! ponds + + TRSNOW*4 & ! snow + n_iso*2 & ! number of isotopes (in ice and snow) + n_aero*4 & ! number of aerosols * 4 aero layers + TRBRI & ! brine height diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 3fecc57cc..63b2afb82 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -88,15 +88,17 @@ subroutine input_data ahmax, R_ice, R_pnd, R_snw, dT_mlt, rsnw_mlt, ksno, & mu_rdg, hs0, dpscale, rfracmin, rfracmax, pndaspect, hs1, hp1, & a_rapid_mode, Rac_rapid_mode, aspect_rapid_mode, dSdt_slow_mode, & - phi_c_slow_mode, phi_i_mushy, kalg, emissivity + phi_c_slow_mode, phi_i_mushy, kalg, emissivity, & + rsnw_fall, rsnw_tmax, rhosnew, rhosmax, & + windmin, drhosdwind integer (kind=int_kind) :: ktherm, kstrength, krdg_partic, krdg_redist, & natmiter, kitd, kcatbound character (len=char_len) :: shortwave, albedo_type, conduct, fbot_xfer_type, & - tfrz_option, frzpnd, atmbndy, wave_spec_type + tfrz_option, frzpnd, atmbndy, wave_spec_type, snwredist - logical (kind=log_kind) :: sw_redist + logical (kind=log_kind) :: sw_redist, use_smliq_pnd real (kind=dbl_kind) :: sw_frac, sw_dtemp ! Flux convergence tolerance @@ -106,11 +108,12 @@ subroutine input_data logical (kind=log_kind) :: conserv_check integer (kind=int_kind) :: ntrcr - logical (kind=log_kind) :: tr_iage, tr_FY, tr_lvl, tr_pond + logical (kind=log_kind) :: tr_iage, tr_FY, tr_lvl, tr_pond, tr_snow logical (kind=log_kind) :: tr_iso, tr_aero, tr_fsd logical (kind=log_kind) :: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, wave_spec integer (kind=int_kind) :: nt_Tsfc, nt_sice, nt_qice, nt_qsno, nt_iage, nt_FY integer (kind=int_kind) :: nt_alvl, nt_vlvl, nt_apnd, nt_hpnd, nt_ipnd, & + nt_smice, nt_smliq, nt_rhos, nt_rsnw, & nt_aero, nt_fsd, nt_isosno, nt_isoice real (kind=real_kind) :: rpcesm, rplvl, rptopo @@ -152,6 +155,10 @@ subroutine input_data rfracmin, rfracmax, pndaspect, hs1, & hp1 + namelist /snow_nml/ & + snwredist, use_smliq_pnd, rsnw_fall, rsnw_tmax, & + rhosnew, rhosmax, windmin, drhosdwind + namelist /forcing_nml/ & atmbndy, calc_strair, calc_Tsfc, & update_ocn_f, l_mpond_fresh, ustar_min, & @@ -173,6 +180,7 @@ subroutine input_data tr_pond_cesm, & tr_pond_lvl, & tr_pond_topo, & + tr_snow, & tr_aero, & tr_fsd, & tr_iso @@ -208,7 +216,12 @@ subroutine input_data tfrz_option_out=tfrz_option, kalg_out=kalg, & fbot_xfer_type_out=fbot_xfer_type, puny_out=puny, & wave_spec_type_out=wave_spec_type, & - sw_redist_out=sw_redist, sw_frac_out=sw_frac, sw_dtemp_out=sw_dtemp) + sw_redist_out=sw_redist, sw_frac_out=sw_frac, sw_dtemp_out=sw_dtemp, & + snwredist_out=snwredist, use_smliq_pnd_out=use_smliq_pnd, & + rsnw_fall_out=rsnw_fall, rsnw_tmax_out=rsnw_tmax, & + rhosnew_out=rhosnew, rhosmax_out=rhosmax, & + windmin_out=windmin, drhosdwind_out=drhosdwind) + call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__, line=__LINE__) @@ -264,7 +277,8 @@ subroutine input_data tr_lvl = .false. ! level ice tr_pond_cesm = .false. ! CESM melt ponds tr_pond_lvl = .false. ! level-ice melt ponds - tr_pond_topo = .false. ! explicit melt ponds (topographic) + tr_pond_topo = .false. ! topographic melt ponds + tr_snow = .false. ! snow tracers (wind redistribution, metamorphosis) tr_aero = .false. ! aerosols tr_fsd = .false. ! floe size distribution tr_iso = .false. ! isotopes @@ -307,6 +321,12 @@ subroutine input_data read(nu_nml, nml=ponds_nml,iostat=nml_error) if (nml_error /= 0) exit + if (tr_snow) then + print*,'Reading snow_nml' + read(nu_nml, nml=snow_nml,iostat=nml_error) + if (nml_error /= 0) exit + endif + print*,'Reading forcing_nml' read(nu_nml, nml=forcing_nml,iostat=nml_error) if (nml_error /= 0) exit @@ -399,6 +419,28 @@ subroutine input_data shortwave = 'dEdd' endif + if (snwredist(1:4) /= 'none' .and. .not. tr_snow) then + write (nu_diag,*) 'WARNING: snwredist on but tr_snow=F' + write (nu_diag,*) 'WARNING: Setting snwredist=none' + snwredist = 'none' + endif + if (snwredist(1:9) == '30percent' .and. .not. tr_lvl) then + write (nu_diag,*) 'WARNING: snwredist=30percent but tr_lvl=F' + write (nu_diag,*) 'WARNING: Setting tr_lvl=T' + tr_lvl = .true. + endif + if (snwredist(1:6) == 'ITDrdg' .and. .not. tr_lvl) then + write (nu_diag,*) 'WARNING: snwredist=ITDrdg but tr_lvl=F' + write (nu_diag,*) 'WARNING: Setting tr_lvl=T' + tr_lvl = .true. + endif + if (use_smliq_pnd .and. .not. tr_snow) then + write (nu_diag,*) 'WARNING: use_smliq_pnd = T but' + write (nu_diag,*) 'WARNING: snow tracers are not active' + write (nu_diag,*) 'WARNING: Setting use_smliq_pnd = F' + use_smliq_pnd = .false. + endif + if (tr_iso .and. n_iso==0) then write (nu_diag,*) 'WARNING: isotopes activated but' write (nu_diag,*) 'WARNING: not allocated in tracer array.' @@ -552,6 +594,17 @@ subroutine input_data if (tr_pond .and. .not. tr_pond_lvl) & write(nu_diag,1000) ' pndaspect = ', pndaspect + if (tr_snow) then + write(nu_diag,1030) ' snwredist = ', snwredist + write(nu_diag,1010) ' use_smliq_pnd = ', use_smliq_pnd + write(nu_diag,1000) ' rsnw_fall = ', rsnw_fall + write(nu_diag,1000) ' rsnw_tmax = ', rsnw_tmax + write(nu_diag,1000) ' rhosnew = ', rhosnew + write(nu_diag,1000) ' rhosmax = ', rhosmax + write(nu_diag,1000) ' windmin = ', windmin + write(nu_diag,1000) ' drhosdwind = ', drhosdwind + endif + write(nu_diag,1020) ' ktherm = ', ktherm if (ktherm == 1) & write(nu_diag,1030) ' conduct = ', conduct @@ -618,6 +671,7 @@ subroutine input_data write(nu_diag,1010) ' tr_pond_cesm = ', tr_pond_cesm write(nu_diag,1010) ' tr_pond_lvl = ', tr_pond_lvl write(nu_diag,1010) ' tr_pond_topo = ', tr_pond_topo + write(nu_diag,1010) ' tr_snow = ', tr_snow write(nu_diag,1010) ' tr_aero = ', tr_aero write(nu_diag,1010) ' tr_fsd = ', tr_fsd @@ -672,6 +726,17 @@ subroutine input_data endif endif + if (tr_snow) then + nt_smice = ntrcr + 1 + ntrcr = ntrcr + nslyr ! mass of ice in nslyr snow layers + nt_smliq = ntrcr + 1 + ntrcr = ntrcr + nslyr ! mass of liquid in nslyr snow layers + nt_rhos = ntrcr + 1 + ntrcr = ntrcr + nslyr ! snow density in nslyr layers + nt_rsnw = ntrcr + 1 + ntrcr = ntrcr + nslyr ! snow grain radius in nslyr layers + endif + nt_fsd = max_ntrcr if (tr_fsd) then nt_fsd = ntrcr + 1 ! floe size distribution @@ -719,7 +784,7 @@ subroutine input_data write(nu_diag,*)' ' 1000 format (a30,2x,f9.2) ! a30 to align formatted, unformatted statements - 1005 format (a30,2x,f10.6) ! float + 1005 format (a30,2x,f10.6) ! float 1010 format (a30,2x,l6) ! logical 1020 format (a30,2x,i6) ! integer 1030 format (a30, a8) ! character @@ -775,13 +840,17 @@ subroutine input_data tfrz_option_in=tfrz_option, kalg_in=kalg, & fbot_xfer_type_in=fbot_xfer_type, & wave_spec_type_in=wave_spec_type, wave_spec_in=wave_spec, & - sw_redist_in=sw_redist, sw_frac_in=sw_frac, sw_dtemp_in=sw_dtemp) + sw_redist_in=sw_redist, sw_frac_in=sw_frac, sw_dtemp_in=sw_dtemp, & + snwredist_in=snwredist, use_smliq_pnd_in=use_smliq_pnd, & + rsnw_fall_in=rsnw_fall, rsnw_tmax_in=rsnw_tmax, & + rhosnew_in=rhosnew, rhosmax_in=rhosmax, & + windmin_in=windmin, drhosdwind_in=drhosdwind) call icepack_init_tracer_sizes(ntrcr_in=ntrcr, & ncat_in=ncat, nilyr_in=nilyr, nslyr_in=nslyr, nblyr_in=nblyr, & nfsd_in=nfsd, n_iso_in=n_iso, n_aero_in=n_aero) call icepack_init_tracer_flags(tr_iage_in=tr_iage, & tr_FY_in=tr_FY, tr_lvl_in=tr_lvl, tr_aero_in=tr_aero, & - tr_iso_in=tr_iso, & + tr_iso_in=tr_iso, tr_snow_in=tr_snow, & tr_pond_in=tr_pond, tr_pond_cesm_in=tr_pond_cesm, & tr_pond_lvl_in=tr_pond_lvl, & tr_pond_topo_in=tr_pond_topo, tr_fsd_in=tr_fsd) @@ -790,6 +859,8 @@ subroutine input_data nt_qsno_in=nt_qsno, nt_iage_in=nt_iage, & nt_fy_in=nt_fy, nt_alvl_in=nt_alvl, nt_vlvl_in=nt_vlvl, & nt_apnd_in=nt_apnd, nt_hpnd_in=nt_hpnd, nt_ipnd_in=nt_ipnd, & + nt_smice_in=nt_smice, nt_smliq_in=nt_smliq, & + nt_rhos_in=nt_rhos, nt_rsnw_in=nt_rsnw, & nt_aero_in=nt_aero, nt_fsd_in=nt_fsd, & nt_isosno_in=nt_isosno, nt_isoice_in=nt_isoice) @@ -875,10 +946,11 @@ subroutine init_state integer (kind=int_kind) :: ntrcr logical (kind=log_kind) :: tr_iage, tr_FY, tr_lvl, tr_aero, tr_fsd, tr_iso - logical (kind=log_kind) :: tr_pond_cesm, tr_pond_lvl, tr_pond_topo + logical (kind=log_kind) :: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow integer (kind=int_kind) :: nt_Tsfc, nt_sice, nt_qice, nt_qsno, nt_iage, nt_fy - integer (kind=int_kind) :: nt_alvl, nt_vlvl, nt_apnd, nt_hpnd, & - nt_ipnd, nt_aero, nt_fsd, nt_isosno, nt_isoice + integer (kind=int_kind) :: nt_alvl, nt_vlvl, nt_apnd, nt_hpnd, nt_ipnd, & + nt_smice, nt_smliq, nt_rhos, nt_rsnw, & + nt_aero, nt_fsd, nt_isosno, nt_isoice character(len=*), parameter :: subname='(init_state)' @@ -890,7 +962,7 @@ subroutine init_state call icepack_query_tracer_sizes(ntrcr_out=ntrcr) call icepack_query_tracer_flags(tr_iage_out=tr_iage, & tr_FY_out=tr_FY, tr_lvl_out=tr_lvl, tr_aero_out=tr_aero, & - tr_iso_out=tr_iso, & + tr_iso_out=tr_iso, tr_snow_out=tr_snow, & tr_pond_cesm_out=tr_pond_cesm, tr_pond_lvl_out=tr_pond_lvl, & tr_pond_topo_out=tr_pond_topo, tr_fsd_out=tr_fsd) call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, & @@ -899,6 +971,8 @@ subroutine init_state nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl, & nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, & nt_ipnd_out=nt_ipnd, & + nt_smice_out=nt_smice, nt_smliq_out=nt_smliq, & + nt_rhos_out=nt_rhos, nt_rsnw_out=nt_rsnw, & nt_isosno_out=nt_isosno, nt_isoice_out=nt_isoice, & nt_aero_out=nt_aero, nt_fsd_out=nt_fsd) call icepack_warnings_flush(nu_diag) @@ -970,6 +1044,14 @@ subroutine init_state trcr_depend(nt_hpnd) = 2+nt_apnd ! melt pond depth trcr_depend(nt_ipnd) = 2+nt_apnd ! refrozen pond lid endif + if (tr_snow) then + do k = 1, nslyr + trcr_depend(nt_smice + k - 1) = 2 ! ice mass in snow + trcr_depend(nt_smliq + k - 1) = 2 ! liquid mass in snow + trcr_depend(nt_rhos + k - 1) = 2 ! effective snow density + trcr_depend(nt_rsnw + k - 1) = 2 ! snow radius + enddo + endif if (tr_fsd) then do it = 1, nfsd trcr_depend(nt_fsd + it - 1) = 0 ! area-weighted floe size distribution diff --git a/configuration/driver/icedrv_restart.F90 b/configuration/driver/icedrv_restart.F90 index 677d28cf3..41990c00e 100644 --- a/configuration/driver/icedrv_restart.F90 +++ b/configuration/driver/icedrv_restart.F90 @@ -16,12 +16,14 @@ module icedrv_restart use icedrv_system, only: icedrv_system_abort implicit none - private :: write_restart_pond_topo, read_restart_pond_topo, & + private :: & write_restart_age, read_restart_age, & write_restart_FY, read_restart_FY, & write_restart_lvl, read_restart_lvl, & write_restart_pond_cesm, read_restart_pond_cesm, & write_restart_pond_lvl, read_restart_pond_lvl, & + write_restart_pond_topo, read_restart_pond_topo, & + write_restart_snow, read_restart_snow, & write_restart_fsd, read_restart_fsd, & write_restart_iso, read_restart_iso, & write_restart_aero, read_restart_aero @@ -63,7 +65,7 @@ subroutine dumpfile logical (kind=log_kind) :: & tr_iage, tr_FY, tr_lvl, tr_iso, tr_aero, tr_brine, & - tr_pond_topo, tr_pond_cesm, tr_pond_lvl, tr_fsd + tr_pond_topo, tr_pond_cesm, tr_pond_lvl, tr_snow, tr_fsd ! solve_zsal, skl_bgc, z_tracers character(len=char_len_long) :: filename @@ -83,7 +85,7 @@ subroutine dumpfile tr_lvl_out=tr_lvl, tr_aero_out=tr_aero, tr_iso_out=tr_iso, & tr_brine_out=tr_brine, & tr_pond_topo_out=tr_pond_topo, tr_pond_cesm_out=tr_pond_cesm, & - tr_pond_lvl_out=tr_pond_lvl,tr_fsd_out=tr_fsd) + tr_pond_lvl_out=tr_pond_lvl,tr_snow_out=tr_snow,tr_fsd_out=tr_fsd) ! call icepack_query_parameters(solve_zsal_out=solve_zsal, & ! skl_bgc_out=skl_bgc, z_tracers_out=z_tracers) call icepack_warnings_flush(nu_diag) @@ -138,6 +140,7 @@ subroutine dumpfile if (tr_pond_cesm) call write_restart_pond_cesm() ! CESM melt ponds if (tr_pond_lvl) call write_restart_pond_lvl() ! level-ice melt ponds if (tr_pond_topo) call write_restart_pond_topo() ! topographic melt ponds + if (tr_snow) call write_restart_snow() ! snow metamorphosis tracers if (tr_iso) call write_restart_iso() ! ice isotopes if (tr_aero) call write_restart_aero() ! ice aerosols if (tr_brine) call write_restart_hbrine() ! brine height @@ -179,7 +182,7 @@ subroutine restartfile (ice_ic) logical (kind=log_kind) :: & tr_iage, tr_FY, tr_lvl, tr_iso, tr_aero, tr_brine, & - tr_pond_topo, tr_pond_cesm, tr_pond_lvl, tr_fsd + tr_pond_topo, tr_pond_cesm, tr_pond_lvl, tr_snow, tr_fsd character(len=char_len_long) :: filename character(len=*), parameter :: subname='(restartfile)' @@ -202,7 +205,7 @@ subroutine restartfile (ice_ic) tr_lvl_out=tr_lvl, tr_aero_out=tr_aero, tr_iso_out=tr_iso, & tr_brine_out=tr_brine, & tr_pond_topo_out=tr_pond_topo, tr_pond_cesm_out=tr_pond_cesm, & - tr_pond_lvl_out=tr_pond_lvl,tr_fsd_out=tr_fsd) + tr_pond_lvl_out=tr_pond_lvl,tr_snow_out=tr_snow,tr_fsd_out=tr_fsd) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) @@ -265,6 +268,7 @@ subroutine restartfile (ice_ic) if (tr_pond_cesm) call read_restart_pond_cesm() ! CESM melt ponds if (tr_pond_lvl) call read_restart_pond_lvl() ! level-ice melt ponds if (tr_pond_topo) call read_restart_pond_topo() ! topographic melt ponds + if (tr_snow) call read_restart_snow() ! snow metamorphosis tracers if (tr_iso) call read_restart_iso() ! ice isotopes if (tr_aero) call read_restart_aero() ! ice aerosols if (tr_brine) call read_restart_hbrine ! brine height @@ -463,6 +467,66 @@ end subroutine read_restart_pond_topo !======================================================================= +! Dumps values needed to restart snow redistribution/metamorphism tracers +! +! authors Elizabeth C. Hunke, LANL + + subroutine write_restart_snow() + + use icedrv_state, only: trcrn + use icedrv_domain_size, only: nslyr, ncat + + integer (kind=int_kind) :: nt_smice, nt_smliq, nt_rhos, nt_rsnw, k + character(len=*), parameter :: subname='(write_restart_snow)' + + call icepack_query_tracer_indices(nt_smice_out=nt_smice, & + nt_smliq_out=nt_smliq, nt_rhos_out=nt_rhos, nt_rsnw_out=nt_rsnw) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & + file=__FILE__,line= __LINE__) + + do k=1,nslyr + call write_restart_field(nu_dump,trcrn(:,nt_smice+k-1,:),ncat) + call write_restart_field(nu_dump,trcrn(:,nt_smliq+k-1,:),ncat) + call write_restart_field(nu_dump,trcrn(:,nt_rhos +k-1,:),ncat) + call write_restart_field(nu_dump,trcrn(:,nt_rsnw +k-1,:),ncat) + enddo + + end subroutine write_restart_snow + +!======================================================================= + +! Reads all values needed to restart snow redistribution/metamorphism +! +! authors Elizabeth C. Hunke, LANL + + subroutine read_restart_snow() + + use icedrv_state, only: trcrn + use icedrv_domain_size, only: nslyr, ncat + + integer (kind=int_kind) :: nt_smice, nt_smliq, nt_rhos, nt_rsnw, k + character(len=*), parameter :: subname='(read_restart_snow)' + + call icepack_query_tracer_indices(nt_smice_out=nt_smice, & + nt_smliq_out=nt_smliq, nt_rhos_out=nt_rhos, nt_rsnw_out=nt_rsnw) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & + file=__FILE__,line= __LINE__) + + write(nu_diag,*) 'min/max snow metamorphosis tracers' + + do k=1,nslyr + call write_restart_field(nu_restart,trcrn(:,nt_smice+k-1,:),ncat) + call write_restart_field(nu_restart,trcrn(:,nt_smliq+k-1,:),ncat) + call write_restart_field(nu_restart,trcrn(:,nt_rhos +k-1,:),ncat) + call write_restart_field(nu_restart,trcrn(:,nt_rsnw +k-1,:),ncat) + enddo + + end subroutine read_restart_snow + +!======================================================================= + ! Dumps all values needed for restarting ! author Elizabeth C. Hunke, LANL diff --git a/configuration/scripts/icepack.build b/configuration/scripts/icepack.build index 24dc40c7d..ddd87cbeb 100755 --- a/configuration/scripts/icepack.build +++ b/configuration/scripts/icepack.build @@ -24,7 +24,7 @@ endif if !(-d ${ICE_OBJDIR}) mkdir -p ${ICE_OBJDIR} cd ${ICE_OBJDIR} -setenv ICE_CPPDEFS "${ICE_CPPDEFS} -DNXGLOB=${ICE_NXGLOB} -DNICELYR=${NICELYR} -DNSNWLYR=${NSNWLYR} -DNICECAT=${NICECAT} -DNFSDCAT=${NFSDCAT} -DTRAGE=${TRAGE} -DTRFY=${TRFY} -DTRLVL=${TRLVL} -DTRPND=${TRPND} -DTRBRI=${TRBRI} -DNTRISO=${NTRISO} -DNTRAERO=${NTRAERO} -DTRZS=${TRZS} -DNBGCLYR=${NBGCLYR} -DTRALG=${TRALG} -DTRBGCZ=${TRBGCZ} -DTRDOC=${TRDOC} -DTRDOC=${TRDOC} -DTRDIC=${TRDIC} -DTRDON=${TRDON} -DTRFED=${TRFED} -DTRFEP=${TRFEP} -DTRZAERO=${TRZAERO} -DTRBGCS=${TRBGCS} " +setenv ICE_CPPDEFS "${ICE_CPPDEFS} -DNXGLOB=${ICE_NXGLOB} -DNICELYR=${NICELYR} -DNSNWLYR=${NSNWLYR} -DNICECAT=${NICECAT} -DNFSDCAT=${NFSDCAT} -DTRAGE=${TRAGE} -DTRFY=${TRFY} -DTRLVL=${TRLVL} -DTRPND=${TRPND} -DTRSNOW=${TRSNOW} -DTRBRI=${TRBRI} -DNTRISO=${NTRISO} -DNTRAERO=${NTRAERO} -DTRZS=${TRZS} -DNBGCLYR=${NBGCLYR} -DTRALG=${TRALG} -DTRBGCZ=${TRBGCZ} -DTRDOC=${TRDOC} -DTRDOC=${TRDOC} -DTRDIC=${TRDIC} -DTRDON=${TRDON} -DTRFED=${TRFED} -DTRFEP=${TRFEP} -DTRZAERO=${TRZAERO} -DTRBGCS=${TRBGCS} " ### List of source code directories (in order of importance). cat >! Filepath << EOF diff --git a/configuration/scripts/icepack.settings b/configuration/scripts/icepack.settings index b1daf38f3..45a93aff1 100755 --- a/configuration/scripts/icepack.settings +++ b/configuration/scripts/icepack.settings @@ -49,6 +49,7 @@ setenv TRAGE 1 # set to 1 for ice age tracer setenv TRFY 1 # set to 1 for first-year ice area tracer setenv TRLVL 1 # set to 1 for level and deformed ice tracers setenv TRPND 1 # set to 1 for melt pond tracers +setenv TRSNOW 1 # set to 1 for snow metamorphism tracers setenv NTRAERO 1 # number of aerosol tracers # (up to max_aero in ice_domain_size.F90) # CESM uses 3 aerosol tracers diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 553ee26e4..683cc4890 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -28,6 +28,7 @@ tr_pond_cesm = .false. tr_pond_topo = .false. tr_pond_lvl = .true. + tr_snow = .false. tr_aero = .false. tr_fsd = .false. tr_iso = .false. @@ -76,6 +77,17 @@ pndaspect = 0.8 / +&snow_nml + snwredist = 'none' + use_smliq_pond = .false. + rsnw_fall = 54.526 + rsnw_tmax = 1500.0 + rhosnew = 100.0 + rhosmax = 450.0 + windmin = 10.0 + drhosdwind = 27.3 +/ + &forcing_nml formdrag = .false. atmbndy = 'default' From c7e889746e8a6761619f86cd64867a47f5853291 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 Aug 2020 16:20:05 -0600 Subject: [PATCH 02/47] snow redistribution testing options --- configuration/scripts/options/set_nml.snw30percent | 2 ++ configuration/scripts/options/set_nml.snwITDrdg | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 configuration/scripts/options/set_nml.snw30percent create mode 100644 configuration/scripts/options/set_nml.snwITDrdg diff --git a/configuration/scripts/options/set_nml.snw30percent b/configuration/scripts/options/set_nml.snw30percent new file mode 100644 index 000000000..c0c52f51a --- /dev/null +++ b/configuration/scripts/options/set_nml.snw30percent @@ -0,0 +1,2 @@ +snwredist = '30percentsw' +nslyr = 3 diff --git a/configuration/scripts/options/set_nml.snwITDrdg b/configuration/scripts/options/set_nml.snwITDrdg new file mode 100644 index 000000000..b8f24b01b --- /dev/null +++ b/configuration/scripts/options/set_nml.snwITDrdg @@ -0,0 +1,2 @@ +snwredist = 'ITDrdg' +nslyr = 3 From ecda5e5952bc0008453c2abaf2cf9b693e987b0f Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 Aug 2020 16:32:38 -0600 Subject: [PATCH 03/47] settings for 3 snow layers, the way Icepack wants them --- configuration/scripts/options/set_env.snw30percent | 1 + configuration/scripts/options/set_env.snwITDrdg | 1 + configuration/scripts/options/set_nml.snw30percent | 2 +- configuration/scripts/options/set_nml.snwITDrdg | 1 - 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 configuration/scripts/options/set_env.snw30percent create mode 100644 configuration/scripts/options/set_env.snwITDrdg diff --git a/configuration/scripts/options/set_env.snw30percent b/configuration/scripts/options/set_env.snw30percent new file mode 100644 index 000000000..d1ddb613d --- /dev/null +++ b/configuration/scripts/options/set_env.snw30percent @@ -0,0 +1 @@ +NSNWLYR 3 # number of vertical layers in the snow diff --git a/configuration/scripts/options/set_env.snwITDrdg b/configuration/scripts/options/set_env.snwITDrdg new file mode 100644 index 000000000..d1ddb613d --- /dev/null +++ b/configuration/scripts/options/set_env.snwITDrdg @@ -0,0 +1 @@ +NSNWLYR 3 # number of vertical layers in the snow diff --git a/configuration/scripts/options/set_nml.snw30percent b/configuration/scripts/options/set_nml.snw30percent index c0c52f51a..793e64153 100644 --- a/configuration/scripts/options/set_nml.snw30percent +++ b/configuration/scripts/options/set_nml.snw30percent @@ -1,2 +1,2 @@ snwredist = '30percentsw' -nslyr = 3 + diff --git a/configuration/scripts/options/set_nml.snwITDrdg b/configuration/scripts/options/set_nml.snwITDrdg index b8f24b01b..6eb1479ac 100644 --- a/configuration/scripts/options/set_nml.snwITDrdg +++ b/configuration/scripts/options/set_nml.snwITDrdg @@ -1,2 +1 @@ snwredist = 'ITDrdg' -nslyr = 3 From 35658ae2d27cf08d466aad4b0bb30dc2fbf6b22c Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 Aug 2020 16:46:10 -0600 Subject: [PATCH 04/47] setenv correction --- configuration/scripts/options/set_env.snw30percent | 4 +++- configuration/scripts/options/set_env.snwITDrdg | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/configuration/scripts/options/set_env.snw30percent b/configuration/scripts/options/set_env.snw30percent index d1ddb613d..bc20eb455 100644 --- a/configuration/scripts/options/set_env.snw30percent +++ b/configuration/scripts/options/set_env.snw30percent @@ -1 +1,3 @@ -NSNWLYR 3 # number of vertical layers in the snow +setenv NSNWLYR 3 # number of vertical layers in the snow + + diff --git a/configuration/scripts/options/set_env.snwITDrdg b/configuration/scripts/options/set_env.snwITDrdg index d1ddb613d..9540293c6 100644 --- a/configuration/scripts/options/set_env.snwITDrdg +++ b/configuration/scripts/options/set_env.snwITDrdg @@ -1 +1,2 @@ -NSNWLYR 3 # number of vertical layers in the snow +setenv NSNWLYR 3 # number of vertical layers in the snow + From a84cb919e6b7421a2f48a38df0d0d96cd984b984 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Sat, 29 Aug 2020 16:38:42 -0600 Subject: [PATCH 05/47] add rhosmin, snwlvlfac to namelist, change snwredist opetion from 30percent to bulk, fix domain size --- columnphysics/icepack_parameters.F90 | 26 ++++++++++++++----- configuration/driver/icedrv_domain_size.F90 | 2 +- configuration/driver/icedrv_init.F90 | 17 +++++++----- configuration/scripts/icepack_in | 18 +++++++------ .../scripts/options/set_nml.snw30percent | 5 +++- .../scripts/options/set_nml.snwITDrdg | 1 + 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index 972894e6b..a9203a6f5 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -322,9 +322,12 @@ module icepack_parameters rsnw_fall = 54.526_dbl_kind, & ! radius of new snow (10^-6 m) rsnw_tmax = 1500.0_dbl_kind, & ! maximum snow radius (10^-6 m) rhosnew = 100.0_dbl_kind, & ! new snow density (kg/m^3) + rhosmin = 100.0_dbl_kind, & ! minimum snow density (kg/m^3) rhosmax = 450.0_dbl_kind, & ! maximum snow density (kg/m^3) windmin = 10.0_dbl_kind, & ! minimum wind speed to compact snow (m/s) - drhosdwind = 27.3_dbl_kind ! wind compaction factor (kg s/m^4) + drhosdwind = 27.3_dbl_kind, & ! wind compaction factor for snow (kg s/m^4) + snwlvlfac = 0.3_dbl_kind ! fractional increase in snow + ! depth for bulk redistribution !----------------------------------------------------------------------- ! Parameters for biogeochemistry @@ -433,7 +436,8 @@ subroutine icepack_init_parameters( & y_sk_DMS_in, t_sk_conv_in, t_sk_ox_in, frazil_scav_in, & sw_redist_in, sw_frac_in, sw_dtemp_in, & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & - rhosnew_in, rhosmax_in, windmin_in, drhosdwind_in) + rhosnew_in, rhosmin_in, rhosmax_in, windmin_in, drhosdwind_in, & + snwlvlfac_in) !----------------------------------------------------------------- ! parameter constants @@ -741,9 +745,11 @@ subroutine icepack_init_parameters( & rsnw_fall_in, & ! radius of new snow (10^-6 m) rsnw_tmax_in, & ! maximum snow radius (10^-6 m) rhosnew_in, & ! new snow density (kg/m^3) + rhosmin_in, & ! minimum snow density (kg/m^3) rhosmax_in, & ! maximum snow density (kg/m^3) windmin_in, & ! minimum wind speed to compact snow (m/s) - drhosdwind_in ! wind compaction factor (kg s/m^4) + drhosdwind_in, & ! wind compaction factor (kg s/m^4) + snwlvlfac_in ! fractional increase in snow depth !autodocument_end @@ -863,9 +869,11 @@ subroutine icepack_init_parameters( & if (present(rsnw_fall_in) ) rsnw_fall = rsnw_fall_in if (present(rsnw_tmax_in) ) rsnw_tmax = rsnw_tmax_in if (present(rhosnew_in) ) rhosnew = rhosnew_in + if (present(rhosmin_in) ) rhosmin = rhosmin_in if (present(rhosmax_in) ) rhosmax = rhosmax_in if (present(windmin_in) ) windmin = windmin_in if (present(drhosdwind_in) ) drhosdwind = drhosdwind_in + if (present(snwlvlfac_in) ) snwlvlfac = snwlvlfac_in if (present(bgc_flux_type_in) ) bgc_flux_type = bgc_flux_type_in if (present(z_tracers_in) ) z_tracers = z_tracers_in if (present(scale_bgc_in) ) scale_bgc = scale_bgc_in @@ -959,7 +967,8 @@ subroutine icepack_query_parameters( & y_sk_DMS_out, t_sk_conv_out, t_sk_ox_out, frazil_scav_out, & sw_redist_out, sw_frac_out, sw_dtemp_out, & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & - rhosnew_out, rhosmax_out, windmin_out, drhosdwind_out) + rhosnew_out, rhosmin_out, rhosmax_out, windmin_out, drhosdwind_out, & + snwlvlfac_out) !----------------------------------------------------------------- ! parameter constants @@ -1276,10 +1285,11 @@ subroutine icepack_query_parameters( & rsnw_fall_out, & ! radius of new snow (10^-6 m) rsnw_tmax_out, & ! maximum snow radius (10^-6 m) rhosnew_out, & ! new snow density (kg/m^3) + rhosmin_out, & ! minimum snow density (kg/m^3) rhosmax_out, & ! maximum snow density (kg/m^3) windmin_out, & ! minimum wind speed to compact snow (m/s) - drhosdwind_out ! wind compaction factor (kg s/m^4) - + drhosdwind_out, & ! wind compaction factor (kg s/m^4) + snwlvlfac_out ! fractional increase in snow depth !autodocument_end character(len=*),parameter :: subname='(icepack_query_parameters)' @@ -1439,9 +1449,11 @@ subroutine icepack_query_parameters( & if (present(rsnw_fall_out) ) rsnw_fall_out = rsnw_fall if (present(rsnw_tmax_out) ) rsnw_tmax_out = rsnw_tmax if (present(rhosnew_out) ) rhosnew_out = rhosnew + if (present(rhosmin_out) ) rhosmin_out = rhosmin if (present(rhosmax_out) ) rhosmax_out = rhosmax if (present(windmin_out) ) windmin_out = windmin if (present(drhosdwind_out) ) drhosdwind_out = drhosdwind + if (present(snwlvlfac_out) ) snwlvlfac_out = snwlvlfac if (present(bgc_flux_type_out) ) bgc_flux_type_out= bgc_flux_type if (present(z_tracers_out) ) z_tracers_out = z_tracers if (present(scale_bgc_out) ) scale_bgc_out = scale_bgc @@ -1625,9 +1637,11 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " rsnw_fall = ", rsnw_fall write(iounit,*) " rsnw_tmax = ", rsnw_tmax write(iounit,*) " rhosnew = ", rhosnew + write(iounit,*) " rhosmin = ", rhosmin write(iounit,*) " rhosmax = ", rhosmax write(iounit,*) " windmin = ", windmin write(iounit,*) " drhosdwind = ", drhosdwind + write(iounit,*) " snwlvlfac = ", snwlvlfac write(iounit,*) " bgc_flux_type = ", bgc_flux_type write(iounit,*) " z_tracers = ", z_tracers write(iounit,*) " scale_bgc = ", scale_bgc diff --git a/configuration/driver/icedrv_domain_size.F90 b/configuration/driver/icedrv_domain_size.F90 index 31b6c734a..9f951272a 100644 --- a/configuration/driver/icedrv_domain_size.F90 +++ b/configuration/driver/icedrv_domain_size.F90 @@ -48,7 +48,7 @@ module icedrv_domain_size + TRFY & ! first-year area + TRLVL*2 & ! level/deformed ice + TRPND*3 & ! ponds - + TRSNOW*4 & ! snow + + TRSNOW*4*nslyr & ! snow redistribution/metamorphism + n_iso*2 & ! number of isotopes (in ice and snow) + n_aero*4 & ! number of aerosols * 4 aero layers + TRBRI & ! brine height diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 63b2afb82..0cc430ffc 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -89,8 +89,8 @@ subroutine input_data mu_rdg, hs0, dpscale, rfracmin, rfracmax, pndaspect, hs1, hp1, & a_rapid_mode, Rac_rapid_mode, aspect_rapid_mode, dSdt_slow_mode, & phi_c_slow_mode, phi_i_mushy, kalg, emissivity, & - rsnw_fall, rsnw_tmax, rhosnew, rhosmax, & - windmin, drhosdwind + rsnw_fall, rsnw_tmax, rhosnew, rhosmin, rhosmax, & + windmin, drhosdwind, snwlvlfac integer (kind=int_kind) :: ktherm, kstrength, krdg_partic, krdg_redist, & natmiter, kitd, kcatbound @@ -157,7 +157,8 @@ subroutine input_data namelist /snow_nml/ & snwredist, use_smliq_pnd, rsnw_fall, rsnw_tmax, & - rhosnew, rhosmax, windmin, drhosdwind + rhosnew, rhosmin, rhosmax, snwlvlfac, & + windmin, drhosdwind namelist /forcing_nml/ & atmbndy, calc_strair, calc_Tsfc, & @@ -219,8 +220,8 @@ subroutine input_data sw_redist_out=sw_redist, sw_frac_out=sw_frac, sw_dtemp_out=sw_dtemp, & snwredist_out=snwredist, use_smliq_pnd_out=use_smliq_pnd, & rsnw_fall_out=rsnw_fall, rsnw_tmax_out=rsnw_tmax, & - rhosnew_out=rhosnew, rhosmax_out=rhosmax, & - windmin_out=windmin, drhosdwind_out=drhosdwind) + rhosnew_out=rhosnew, rhosmin_out = rhosmin, rhosmax_out=rhosmax, & + windmin_out=windmin, drhosdwind_out=drhosdwind, snwlvlfac_out=snwlvlfac) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -600,9 +601,11 @@ subroutine input_data write(nu_diag,1000) ' rsnw_fall = ', rsnw_fall write(nu_diag,1000) ' rsnw_tmax = ', rsnw_tmax write(nu_diag,1000) ' rhosnew = ', rhosnew + write(nu_diag,1000) ' rhosmin = ', rhosmin write(nu_diag,1000) ' rhosmax = ', rhosmax write(nu_diag,1000) ' windmin = ', windmin write(nu_diag,1000) ' drhosdwind = ', drhosdwind + write(nu_diag,1000) ' snwlvlfac = ', snwlvlfac endif write(nu_diag,1020) ' ktherm = ', ktherm @@ -843,8 +846,8 @@ subroutine input_data sw_redist_in=sw_redist, sw_frac_in=sw_frac, sw_dtemp_in=sw_dtemp, & snwredist_in=snwredist, use_smliq_pnd_in=use_smliq_pnd, & rsnw_fall_in=rsnw_fall, rsnw_tmax_in=rsnw_tmax, & - rhosnew_in=rhosnew, rhosmax_in=rhosmax, & - windmin_in=windmin, drhosdwind_in=drhosdwind) + rhosnew_in=rhosnew, rhosmin_in=rhosmin, rhosmax_in=rhosmax, & + windmin_in=windmin, drhosdwind_in=drhosdwind, snwlvlfac_in=snwlvlfac) call icepack_init_tracer_sizes(ntrcr_in=ntrcr, & ncat_in=ncat, nilyr_in=nilyr, nslyr_in=nslyr, nblyr_in=nblyr, & nfsd_in=nfsd, n_iso_in=n_iso, n_aero_in=n_aero) diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 683cc4890..b95a68362 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -78,14 +78,16 @@ / &snow_nml - snwredist = 'none' - use_smliq_pond = .false. - rsnw_fall = 54.526 - rsnw_tmax = 1500.0 - rhosnew = 100.0 - rhosmax = 450.0 - windmin = 10.0 - drhosdwind = 27.3 + snwredist = 'none' + use_smliq_pnd = .false. + rsnw_fall = 54.526 + rsnw_tmax = 1500.0 + rhosnew = 100.0 + rhosmin = 100.0 + rhosmax = 450.0 + windmin = 10.0 + drhosdwind = 27.3 + snwlvlfac = 0.3 / &forcing_nml diff --git a/configuration/scripts/options/set_nml.snw30percent b/configuration/scripts/options/set_nml.snw30percent index 793e64153..7461f2b44 100644 --- a/configuration/scripts/options/set_nml.snw30percent +++ b/configuration/scripts/options/set_nml.snw30percent @@ -1,2 +1,5 @@ -snwredist = '30percentsw' +tr_snow = .true. +snwredist = 'bulk' +snwlvlfac = 0.3 + diff --git a/configuration/scripts/options/set_nml.snwITDrdg b/configuration/scripts/options/set_nml.snwITDrdg index 6eb1479ac..509cd403c 100644 --- a/configuration/scripts/options/set_nml.snwITDrdg +++ b/configuration/scripts/options/set_nml.snwITDrdg @@ -1 +1,2 @@ +tr_snow = .true. snwredist = 'ITDrdg' From f2087863b7bed7bebd24f5684b9172f0974f45bf Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Tue, 1 Sep 2020 16:37:42 -0600 Subject: [PATCH 06/47] add ice_snow module; compiles, no hooks from main code, module conversion for Icepack incomplete --- columnphysics/ice_snow.F90 | 914 +++++++++++++++++++++++ columnphysics/icepack_therm_vertical.F90 | 3 +- 2 files changed, 916 insertions(+), 1 deletion(-) create mode 100644 columnphysics/ice_snow.F90 diff --git a/columnphysics/ice_snow.F90 b/columnphysics/ice_snow.F90 new file mode 100644 index 000000000..5667d36df --- /dev/null +++ b/columnphysics/ice_snow.F90 @@ -0,0 +1,914 @@ +!======================================================================= +! +! snow redistribution and metamorphism +! +! authors Elizabeth Hunke, LANL +! Nicole Jeffery, LANL +! + module icepack_snow + + use icepack_kinds + use icepack_parameters, only: puny, p1, p5, c0, c1, c4, c10, c100, pi + use icepack_parameters, only: rhos, rhow, rhoi, rhofresh, rhosmin + use icepack_parameters, only: snwlvlfac, Tffresh, cp_ice, Lfresh + + use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort + + implicit none + private + +! public :: snow_effective_density, update_snow_radius, snow_redist, & +! drain_snow + + real (kind=dbl_kind), parameter, public :: & + S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) + S_wet= 0.422_dbl_kind ! (um^3/s) wet metamorphism parameters + +! character(len=5), parameter, public :: & +! snwredist = 'ITDrdg' ! + +!======================================================================= + + contains + +!======================================================================= + +! Compute effective density of snow layers from ice, liquid water mass + + subroutine snow_effective_density(nslyr, ncat, & + vsnon, vsno, & + smice, smliq, & + rhosnew, & + rhos_effn, rhos_eff, & + rhos_cmpn, rhos_cmp) + + integer (kind=int_kind), intent(in) :: & + nslyr, & ! number of snow layers + ncat ! number of thickness categories + + real (kind=dbl_kind), dimension(:), intent(in) :: & + vsnon ! snow volume (m) + + real (kind=dbl_kind), intent(in) :: & + vsno , & ! total snow volume (m) + rhosnew ! new snow density (kg/m^3) + + real (kind=dbl_kind), dimension(:,:), & + intent(inout) :: & + smice , & ! mass of ice in snow (kg/m^3) + smliq , & ! mass of liquid in snow (kg/m^3) + rhos_effn, & ! effective snow density: content (kg/m^3) + rhos_cmpn ! effective snow density: compaction (kg/m^3) + + real (kind=dbl_kind), intent(inout) :: & + rhos_eff , & ! mean effective snow density: content (kg/m^3) + rhos_cmp ! mean effective snow density: compaction (kg/m^3) + + integer (kind=int_kind) :: & + k , & ! snow layer index + n , & ! ice thickness category index + cnt ! counter for snow presence + + character (len=*),parameter :: subname='(snow_effective_density)' + + rhos_eff = c0 + rhos_cmp = c0 + + if (vsno > puny) then + + !----------------------------------------------------------------- + ! Initialize effective snow density (compaction) for new snow + !----------------------------------------------------------------- + + do n = 1, ncat + do k = 1, nslyr + if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew + enddo + enddo + + !----------------------------------------------------------------- + ! Compute average effective density of snow + !----------------------------------------------------------------- + + do n = 1, ncat + if (vsnon(n) > c0) then + do k = 1, nslyr + rhos_effn(k,n) = rhos_effn(k,n) + smice(k,n) + smliq(k,n) + rhos_eff = rhos_eff + vsnon(n)*rhos_effn(k,n) + rhos_cmp = rhos_cmp + vsnon(n)*rhos_cmpn(k,n) + enddo + endif + enddo + rhos_eff = rhos_eff/(vsno*real(nslyr,kind=dbl_kind)) + rhos_cmp = rhos_cmp/(vsno*real(nslyr,kind=dbl_kind)) + + endif ! vsno + + end subroutine snow_effective_density + +!======================================================================= + +! Snow redistribution by wind, based on O. Lecomte Ph.D. (2014). +! The original formulation: +! Snow in suspension depends on wind speed, density and the standard +! deviation of the ice thickness distribution. Snow is redistributed +! among ice categories proportionally to the category areas. +! +! Namelist option snwredist = 'ITDrdg' modifies the approach to use +! the level and ridged ice tracers: +! As above, but use the standard deviation of the level and ridged +! ice thickness distribution for snow in suspension, and redistribute +! based on ridged ice area. +! +! convention: +! volume, mass and energy include factor of ain +! thickness does not + + subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & + snwredist, alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, & + fsnow, rhosmax, windmin, drhosdwind) + + use icepack_therm_vertical, only: adjust_enthalpy + + integer (kind=int_kind), intent(in) :: & + nslyr , & ! number of snow layers + ncat ! number of thickness categories + + real (kind=dbl_kind), intent(in) :: & + dt , & ! time step (s) + wind , & ! wind speed (m/s) + fsnow , & ! snowfall rate (kg m-2 s-1) + rhosmax , & ! maximum snow density (kg/m^3) + windmin , & ! minimum wind speed to compact snow (m/s) + drhosdwind ! wind compaction factor (kg s/m^4) + + real (kind=dbl_kind), dimension(:), intent(in) :: & + ain , & ! ice area fraction + vin , & ! ice volume (m) + alvl , & ! level ice area tracer + vlvl ! level ice volume tracer + + real (kind=dbl_kind), intent(inout) :: & + fresh , & ! fresh water flux to ocean (kg/m^2/s) + fhocn , & ! net heat flux to ocean (W/m^2) + fsloss ! snow loss to leads (kg/m^2/s) + + real (kind=dbl_kind), dimension(:), intent(inout) :: & + vsn ! snow volume (m) + + real (kind=dbl_kind), dimension(:,:), intent(inout) :: & + zqsn , & ! snow enthalpy (J/m^3) + rhos_cmpn ! effective snow density: compaction (kg/m^3) + + character(len=char_len), intent(in) :: & + snwredist ! type of snow redistribution + + ! local variables + + integer (kind=int_kind) :: & + n , & ! category index + k ! layer index + + integer (kind=int_kind), dimension(ncat) :: & + klyr ! layer index + + real (kind=dbl_kind), parameter :: & + refsd = c1 , & ! standard deviation reference + gamma = 1.e-5_dbl_kind ! tuning coefficient + + real (kind=dbl_kind) :: & + Vseas , & ! critical seasonal wind speed (m/s) + ITDsd , & ! standard deviation of ITD + flost , & ! fraction of snow lost in leads + alost , & ! effective lead area for snow lost in leads + suma , & ! sum of ice area over categories + sumv , & ! sum of ice volume over categories (m) + summ , & ! sum of snow mass over categories (kg/m^2) + sumq , & ! sum of snow enthalpy over categories (kg/m^2) + msusp , & ! potential mass of snow in suspension (kg/m^2) + msnw_susp , & ! mass of snow in suspension (kg/m^2) + esnw_susp , & ! energy of snow in suspension (J/m^2) + asnw_lvl , & ! mass of snow redeposited on level ice (kg/m^2) + e_redeptmp, & ! redeposited energy (J/m^2) + dhsn , & ! change in snow depth (m) + dmp , & ! mass difference in previous layer (kg/m^2) + hslyr , & ! snow layer thickness (m) + hslab , & ! new snow thickness (m) + drhos , & ! change in snow density due to compaction (kg/m^3) + mlost , & ! mass of suspended snow lost in leads (kg/m^2) + elost , & ! energy of suspended snow lost in leads (J/m^2) + de , & ! change in energy (J/m^2) + al, ar , & ! areas of level and ridged ice + hlvl, hrdg, & ! thicknesses of level and ridged ice + tmp1, tmp2, & ! temporary values + tmp3, tmp4, & ! temporary values + tmp5 , & ! temporary values + work ! temporary value + + real (kind=dbl_kind), dimension(ncat) :: & + sfac , & ! temporary for snwlvlfac + ardg , & ! ridged ice area tracer + m_erosion , & ! eroded mass (kg/m^2) + e_erosion , & ! eroded energy (J/m^2) + m_redep , & ! redeposited mass (kg/m^2) + e_redep , & ! redeposited energy (J/m^2) + vsn_init , & ! initial volume (m) + esn_init , & ! initial energy (J/m^2) + esn_final , & ! final energy (J/m^2) + atmp , & ! temporary variable for ain, for debugging convenience + hin , & ! ice thickness (m) + hsn , & ! snow depth (m) + hsn_new ! new snow depth (m) + + real (kind=dbl_kind), dimension (nslyr) :: & + dzs ! snow layer thickness after redistribution (m) + + real (kind=dbl_kind), dimension (nslyr+1) :: & + zs1 , & ! depth of snow layer boundaries (m) + zs2 ! adjusted depths, with equal hslyr (m) + + character (len=*),parameter :: subname='(snow_redist)' + + !----------------------------------------------------------------- + ! Conservation checks + !----------------------------------------------------------------- + + tmp1 = c0 + tmp3 = c0 + do n = 1, ncat + ! mass conservation check + tmp1 = tmp1 + vsn(n) + vsn_init(n) = vsn(n) + esn_init(n) = c0 + ! energy conservation check + do k = 1, nslyr + tmp3 = tmp3 + vsn(n)*zqsn(k,n)/nslyr + esn_init(n) = esn_init(n) + vsn(n)*zqsn(k,n)/nslyr + enddo + enddo + + !----------------------------------------------------------------- + ! category thickness and sums + !----------------------------------------------------------------- + + hin(:) = c0 + hsn(:) = c0 + suma = c0 + sumv = c0 + do n = 1, ncat + atmp(n) = ain(n) + if (atmp(n) > puny) then + hin(n) = vin(n)/atmp(n) + hsn(n) = vsn(n)/atmp(n) + endif + hsn_new(n) = hsn(n) + suma = suma + atmp(n) + sumv = sumv + vin(n) + ! maintain positive definite enthalpy + do k = 1, nslyr + zqsn(k,n) = min(zqsn(k,n) + Lfresh*rhos, c0) + enddo + enddo ! ncat + + !----------------------------------------------------------------- + ! standard deviation of ice thickness distribution + !----------------------------------------------------------------- + + work = c0 + asnw_lvl = c0 + if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice + do n = 1, ncat + ardg(n) = c1 - alvl(n) ! ridged ice tracer + al = alvl(n) * atmp(n) ! level + ar = ardg(n) * atmp(n) ! ridged + hlvl = c0 + hrdg = c0 + if (al > puny) hlvl = vin(n)*vlvl(n)/al + if (ar > puny) hrdg = vin(n)*(c1-vlvl(n))/ar + work = work + al*(hlvl - sumv)**2 + ar*(hrdg - sumv)**2 + + ! for redeposition of snow on level ice + sfac(n) = snwlvlfac + if (ardg(n) > c0) sfac(n) = min(snwlvlfac, alvl(n)/ardg(n)) + asnw_lvl = asnw_lvl + al - sfac(n)*ar + enddo + asnw_lvl = asnw_lvl/suma +! else ! snwredist = 'ITDsd' ! use standard ITD +! do n = 1, ncat +! work = work + atmp(n)*(hin(n) - sumv)**2 +! enddo + endif + ITDsd = sqrt(work) + + !----------------------------------------------------------------- + ! fraction of suspended snow lost in leads + !----------------------------------------------------------------- + + flost = (c1 - suma) * exp(-ITDsd/refsd) +!echmod flost = c0 + alost = c1 - suma * (c1-flost) + + !----------------------------------------------------------------- + ! suspended snow + !----------------------------------------------------------------- + + msusp = c0 + do n = 1, ncat + ! critical seasonal wind speed needed to compact snow to density rhos + Vseas = (rhos_cmpn(1,n) - 44.6_dbl_kind)/174.0_dbl_kind ! use top layer + Vseas = max(Vseas, c0) + ! maximum mass per unit area of snow in suspension (kg/m^2) + if (ITDsd > puny) & + msusp = msusp + atmp(n)*gamma*dt*max(wind-Vseas,c0) & + * (rhosmax-rhos_cmpn(1,n))/(rhosmax*ITDsd) + enddo + + !----------------------------------------------------------------- + ! erosion + !----------------------------------------------------------------- + + msnw_susp = c0 + esnw_susp = c0 + klyr(:) = 1 + do n = 1, ncat + m_erosion(n) = c0 ! mass + e_erosion(n) = c0 ! energy + if (atmp(n) > puny) then + m_erosion(n) = min(msusp, rhos*vsn(n)) + if (m_erosion(n) > puny) then + summ = c0 + dmp = m_erosion(n) + do k = 1, nslyr + if (dmp > c0) then + dhsn = min(hsn(n)/nslyr, dmp/(rhos*atmp(n))) + msnw_susp = msnw_susp + dhsn*rhos*atmp(n) ! total mass in suspension + hsn_new(n) = hsn_new(n) - dhsn + e_erosion(n) = e_erosion(n) + dhsn*zqsn(k,n)*atmp(n) + klyr(n) = k ! number of affected layers + summ = summ + rhos*vsn(n)/nslyr ! mass, partial sum + dmp = max(m_erosion(n) - summ, c0) + endif ! dmp + enddo + esnw_susp = esnw_susp + e_erosion(n) ! total energy in suspension + endif + endif + enddo + + !----------------------------------------------------------------- + ! redeposition + !----------------------------------------------------------------- + + do n = 1, ncat + if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice + work = atmp(n)*(c1-flost)*(ardg(n)*(c1+sfac(n)) + asnw_lvl) + else ! use standard ITD + work = atmp(n)*(c1-flost) + endif + m_redep(n) = msnw_susp*work ! mass + e_redep(n) = c0 + e_redeptmp = esnw_susp*work ! energy + + ! change in snow depth + dhsn = c0 + if (atmp(n) > puny) then + dhsn = m_redep(n) / (rhos*atmp(n)) + + if (abs(dhsn) > c0) then + + e_redep(n) = e_redeptmp + vsn(n) = (hsn_new(n)+dhsn)*atmp(n) + + ! change in snow energy + de = e_redeptmp / klyr(n) + ! spread among affected layers + sumq = c0 + do k = 1, klyr(n) + zqsn(k,n) = (atmp(n)*hsn_new(n)*zqsn(k,n) + de) & + / (vsn(n)) ! factor of nslyr cancels out + + if (zqsn(k,n) > c0) then + sumq = sumq + zqsn(k,n) + zqsn(k,n) = c0 + endif + + enddo ! klyr + zqsn(klyr(n),n) = min(zqsn(klyr(n),n) + sumq, c0) ! may lose energy here + + !----------------------------------------------------------------- + ! Conserving energy, compute the enthalpy of the new equal layers + !----------------------------------------------------------------- + + if (nslyr > 1) then + + dzs(:) = hsn(n) / real(nslyr,kind=dbl_kind) ! old layer thickness + do k = 1, klyr(n) + dzs(k) = dzs(k) + dhsn / klyr(n) ! old layer thickness (updated) + enddo + hsn_new(n) = hsn_new(n) + dhsn + hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind) ! new layer thickness + + zs1(1) = c0 + zs1(1+nslyr) = hsn_new(n) + + zs2(1) = c0 + zs2(1+nslyr) = hsn_new(n) + + do k = 1, nslyr-1 + zs1(k+1) = zs1(k) + dzs(k) ! old layer depths (unequal thickness) + zs2(k+1) = zs2(k) + hslyr ! new layer depths (equal thickness) + enddo + + call adjust_enthalpy (nslyr, & + zs1(:), zs2(:), & + hslyr, hsn_new(n), & + zqsn(:,n)) + endif ! nslyr > 1 + endif ! |dhsn| > puny + endif ! ain > puny + + ! maintain positive definite enthalpy + do k = 1, nslyr + zqsn(k,n) = zqsn(k,n) - Lfresh*rhos + enddo + enddo ! ncat + + !----------------------------------------------------------------- + ! mass of suspended snow lost in leads + !----------------------------------------------------------------- + mlost = msnw_susp*alost + fsloss = fsloss + mlost / dt + + !----------------------------------------------------------------- + ! mass conservation check + !----------------------------------------------------------------- + + tmp2 = c0 + do n = 1, ncat + tmp2 = tmp2 + vsn(n) + enddo + + if (tmp2 > tmp1) then ! correct roundoff error + vsn(:) = vsn(:) * tmp1/tmp2 + tmp2 = c0 + do n = 1, ncat + tmp2 = tmp2 + vsn(n) + enddo + endif + + if (tmp2 < tmp1) fresh = fresh + rhos*(tmp1-tmp2)/dt + + tmp2 = tmp2 + (mlost/rhos) + + if (abs(tmp1-tmp2) > puny) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: snow redistribution mass conservation error') +! write(warning,*)'mass conservation error in snow_redist', tmp1, tmp2 +! write(warning,*)'klyr',klyr +! write(warning,*)'ain',atmp(:) +! write(warning,*)'vsn final',vsn(:) +! write(warning,*)'vsn init',vsn_init(:) +! write(warning,*)'rhos*vsn init',rhos*vsn_init(:) +! write(warning,*)'m_erosion',m_erosion(:) +! write(warning,*)'m_redep',m_redep(:) +! write(warning,*)'mlost',mlost +! write(warning,*)'v_erosion',m_erosion(:)/rhos +! write(warning,*)'v_redep',m_redep(:)/rhos +! write(warning,*)'v lost',mlost/rhos +! write(warning,*)'hsn',hsn(:) +! write(warning,*)'hsn_new',hsn_new(:) +! write(warning,*)'vsn_new',hsn_new(:)*atmp(:) +! write(warning,*)'lost',suma,flost,alost,msnw_susp + endif + + !----------------------------------------------------------------- + ! energy conservation check + !----------------------------------------------------------------- + + tmp4 = c0 + tmp5 = c0 + esn_final(:) = c0 + do n = 1, ncat + do k = 1, nslyr + tmp4 = tmp4 + vsn(n)*zqsn(k,n)/nslyr + esn_final(n) = esn_final(n) + vsn(n)*zqsn(k,n)/nslyr + enddo + tmp5 = tmp5 - e_erosion(n) + e_redep(n) + enddo + tmp5 = tmp5 + esnw_susp*alost + + !----------------------------------------------------------------- + ! energy of suspended snow lost in leads + !----------------------------------------------------------------- + elost = tmp3 - tmp4 + fhocn = fhocn + elost / dt + + if (abs(tmp5) > nslyr*Lfresh*puny) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: snow redistribution energy conservation error') +! write(warning,*)'energy conservation error in snow_redist', tmp3, tmp4, tmp5 +! write(warning,*)'klyr',klyr +! write(warning,*)'ain',atmp(:) +! write(warning,*)'vsn final',vsn(:) +! write(warning,*)'vsn init',vsn_init(:) +! write(warning,*)'rhos*vsn init',rhos*vsn_init(:) +! write(warning,*)'m_erosion',m_erosion(:) +! write(warning,*)'m_redep',m_redep(:) +! write(warning,*)'mlost',mlost +! write(warning,*)'v_erosion',m_erosion(:)/rhos +! write(warning,*)'v_redep',m_redep(:)/rhos +! write(warning,*)'v lost',mlost/rhos +! write(warning,*)'hsn',hsn(:) +! write(warning,*)'hsn_new',hsn_new(:) +! write(warning,*)'vsn_new',hsn_new(:)*atmp(:) +! write(warning,*)'lost',suma,flost,alost,msnw_susp +! write(warning,*)'tmp3(1)', (vsn(1)*zqsn(k,1)/nslyr,k=1,nslyr) +! write(warning,*)'esn init',esn_init(:) +! write(warning,*)'esn final',esn_final(:) +! write(warning,*)'e_erosion',e_erosion(:) +! write(warning,*)'e_redep',e_redep(:) +! write(warning,*)'elost',elost,esnw_susp*alost,Lfresh*mlost +! write(warning,*)'esnw_susp',esnw_susp + endif + + !----------------------------------------------------------------- + ! wind compaction + !----------------------------------------------------------------- + + do n = 1, ncat + if (vsn(n) > puny) then + ! compact freshly fallen or redistributed snow + drhos = drhosdwind * max(wind - windmin, c0) + hslab = c0 + if (fsnow > c0) & + hslab = max(min(fsnow*dt/(rhos+drhos), hsn_new(n)-hsn(n)), c0) + hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind) + do k = 1, nslyr + work = hslab - hslyr * real(k-1,kind=dbl_kind) + work = max(c0, min(hslyr, work)) + rhos_cmpn(k,n) = rhos_cmpn(k,n) + drhos*work/hslyr + rhos_cmpn(k,n) = min(rhos_cmpn(k,n), rhosmax) + enddo + endif + enddo + + end subroutine snow_redist + +!======================================================================= + +! Snow grain metamorphism driver + + subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & + Tsfc, zTin, & + hsn, zqsn, smice, smliq, & + rsnw_fall, rsnw_tmax, & + snowage_tau, & + snowage_kappa, & + snowage_drdt0, & + idx_T_max, & + idx_Tgrd_max, & + idx_rhos_max) + + integer (kind=int_kind), intent(in) :: & + ncat, & ! number of categories + nslyr, & ! number of snow layers + nilyr, & ! number of ice layers + idx_T_max, & ! dimensions of snow parameter matrix + idx_Tgrd_max, & + idx_rhos_max + + real (kind=dbl_kind), intent(in) :: & + dt ! time step + + real (kind=dbl_kind), dimension(ncat), intent(in) :: & + zTin , & ! surface ice temperature (oC) + Tsfc , & ! surface temperature (oC) + hin , & ! ice thickness (m) + hsn ! snow thickness (m) + + real (kind=dbl_kind), dimension(nslyr,ncat), intent(in) :: & + zqsn ! enthalpy of snow (J m-3) + + real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: & + rsnw + + real (kind=dbl_kind), dimension(nslyr,ncat), & + intent(inout) :: & + smice, & ! mass of ice in snow (kg/m^2) + smliq ! mass of liquid in snow (kg/m^2) + + real (kind=dbl_kind), intent(in) :: & + rsnw_fall, & ! radius of newly fallen snow (10^-6 m) + rsnw_tmax ! maximum grain radius from dry metamorphism (10^-6 m) + + ! dry snow aging parameters + real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: & + snowage_tau, & ! (10^-6 m) + snowage_kappa, & ! + snowage_drdt0 ! (10^-6 m/hr) + + ! local temporary variables + + integer (kind=int_kind) :: k, n + + real (kind=dbl_kind), dimension(nslyr) :: & + drsnw_wet, & ! wet metamorphism (10^-6 m) + drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m) + + character (len=*),parameter :: subname='(update_snow_radius)' + + do n = 1, ncat + + if (hsn(n) > puny .and. hin(n) > puny) then + + drsnw_dry(:) = c0 + drsnw_wet(:) = c0 + + !----------------------------------------------------------------- + ! dry metamorphism + !----------------------------------------------------------------- + call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & + drsnw_dry, zqsn(:,n), Tsfc(n), & + zTin(n), hsn(n), hin(n), & + smice(:,n), smliq(:,n), rsnw_fall, & + snowage_tau, snowage_kappa, snowage_drdt0, & + idx_T_max, idx_Tgrd_max, idx_rhos_max) + + !----------------------------------------------------------------- + ! wet metamorphism + !----------------------------------------------------------------- + do k = 1,nslyr + call snow_wet_metamorph (dt, drsnw_wet(k), rsnw(k,n), & + smice(k,n), smliq(k,n)) + rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k)) + enddo + + else + do k = 1,nslyr + ! rsnw_fall < rsnw < rsnw_tmax + rsnw(k,n) = max(rsnw_fall,min(rsnw_tmax, rsnw(k,n))) + smice(k,n) = rhos + smliq(k,n) = c0 + enddo + endif + enddo + + end subroutine update_snow_radius + +!======================================================================= + +! Snow grain metamorphism + + subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & + Tsfc, zTin1, hsn, hin, smice, smliq, rsnw_fall, & + snowage_tau, snowage_kappa, snowage_drdt0, & + idx_T_max, idx_Tgrd_max, idx_rhos_max) + + ! Vapor redistribution: Method is to retrieve 3 best-bit parameters that + ! depend on snow temperature, temperature gradient, and density, + ! that are derived from the microphysical model described in: + ! Flanner and Zender (2006), Linking snowpack microphysics and albedo + ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834. + ! The parametric equation has the form: + ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where: + ! r is the effective radius, + ! tau and kappa are best-fit parameters, + ! drdt_0 is the initial rate of change of effective radius, and + ! dr_fresh is the difference between the current and fresh snow states + ! (r_current - r_fresh). + + integer (kind=int_kind), intent(in) :: & + nslyr, & ! number of snow layers + nilyr, & ! number of ice layers + idx_T_max, & ! dimensions of snow parameter matrix + idx_Tgrd_max, & + idx_rhos_max + + real (kind=dbl_kind), intent(in) :: & + dt ! time step (s) + + real (kind=dbl_kind), dimension(nslyr), & + intent(in) :: & + smice , & ! mass of ice in snow (kg/m^3) + smliq , & ! mass of liquid in snow (kg/m^3) + rsnw, & ! snow grain radius (10^-6 m) + zqsn ! snow enthalpy (J m-3) + + real (kind=dbl_kind), dimension(nslyr), & + intent(inout) :: & + drsnw_dry ! change due to snow aging (10^-6 m) + + real (kind=dbl_kind), intent(in) :: & + Tsfc, & ! surface temperature (oC) + zTin1, & ! top ice layer temperature (oC) + hsn, & ! snow thickness (m) + hin, & ! ice thickness (m) + rsnw_fall + + ! dry snow aging parameters + real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: & + snowage_tau, & ! (10^-6 m) + snowage_kappa, & ! + snowage_drdt0 ! (10^-6 m/hr) + + ! local temporary variables + + integer (kind=int_kind) :: k + + integer (kind=int_kind) :: & + T_idx, & ! temperature index + Tgrd_idx, & ! temperature gradient index + rhos_idx ! density index + + real (kind=dbl_kind), dimension(nslyr):: & + zrhos, & ! snow density (kg/m^3) ! for variable snow density + zdTdz, & ! temperature gradient (K/s) + zTsn ! snow temperature (oC) + + real (kind=dbl_kind) :: & + bst_tau, & ! snow aging parameter retrieved from lookup table [hour] + bst_kappa, & ! snow aging parameter retrieved from lookup table [unitless] + bst_drdt0, & ! snow aging parameter retrieved from lookup table [um hr-1] + dr_fresh, & ! change in snow radius from fresh (10^-6 m) + dzs, & ! snow layer thickness (m) + dzi ! ice layer thickness (m) + + character (len=*),parameter :: subname='(snow_dry_metamorph)' + +! Needed for variable snow density not currently modeled +! calculate density based on liquid and ice content of snow + + drsnw_dry(:) = c0 + zTsn(:) = c0 + zdTdz(:) = c0 + zrhos(:) = rhos + + dzs = hsn/real(nslyr,kind=dbl_kind) + dzi = hin/real(nilyr,kind=dbl_kind) + + zTsn(1) = (Lfresh + zqsn(1)/rhos)/cp_ice + if (nslyr == 1) then + zdTdz(1) = min(c10*idx_Tgrd_max, & + abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny)) + else + zTsn(1) =(Lfresh + zqsn(1)/rhos)/cp_ice +!ech fix this loop - remove if/else/endif + do k = 2, nslyr + zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice + if (k == 2) then + zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny) + zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1)) + else + zdTdz(k-1) = abs(zTsn(k-2)-zTsn(k))*p5/(dzs+puny) + zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1)) + endif + enddo + zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) & + - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny) + zdTdz(nslyr) = min(c10*idx_Tgrd_max, zdTdz(nslyr)) + endif + + ! best-fit parameters are read from a table + ! 11 temperatures from 225 to 273 K + ! 31 temperature gradients from 0 to 300 K/m + ! 8 snow densities from 0 to 350 kg/m3 + ! pointer snowage_tau, snowage_kappa, snowage_drdt0 + + do k = 1, nslyr + zrhos(k) = smice(k) + smliq(k) + + ! best-fit table indecies: + T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind) + Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind) + !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! variable density + rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! fixed density + + ! boundary check: + T_idx = min(idx_T_max, max(1,T_idx+1))!min(idx_T_max, max(idx_T_min,T_idx)) + Tgrd_idx = min(idx_Tgrd_max, max(1,Tgrd_idx+1))!min(idx_Tgrd_max, max(idx_Tgrd_min,Tgrd_idx)) + rhos_idx = min(idx_rhos_max, max(1,rhos_idx+1)) !min(idx_rhos_max, max(idx_rhos_min,rhos_idx)) + + bst_tau = snowage_tau(rhos_idx,Tgrd_idx,T_idx) + bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx) + bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx) + + ! change in snow effective radius, using best-fit parameters + dr_fresh = max(c0,rsnw(k)-rsnw_fall) + drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))& + * (dt/3600.0_dbl_kind) + enddo + + end subroutine snow_dry_metamorph + +!======================================================================= + +! Snow grain metamorphism + + subroutine snow_wet_metamorph (dt, dr_wet, rsnw, smice, smliq) + ! + ! Liquid water redistribution: Apply the grain growth function from: + ! Brun, E. (1989), Investigation of wet-snow metamorphism in respect of + ! liquid-water content, Annals of Glaciology, 13, 22-26. + ! There are two parameters that describe the grain growth rate as + ! a function of snow liquid water content (LWC). The "LWC=0" parameter + ! is zeroed here because we are accounting for dry snowing with a + ! different representation + ! + real (kind=dbl_kind), intent(in) :: & + dt ! time step + + real (kind=dbl_kind), intent(in) :: & + rsnw , & ! snow grain radius (10^-6 m) + smice, & ! snow ice density (kg/m^3) + smliq ! snow liquid density (kg/m^3) + + real (kind=dbl_kind), intent(inout) :: & + dr_wet + + real (kind=dbl_kind) :: & + fliq ! liquid mass fraction + + character (len=*),parameter :: subname='(snow_wet_metamorph)' + + dr_wet = c0 + fliq = c1 + if (smice + smliq > c0 .and. rsnw > c0) then + fliq = min(smliq/(smice + smliq),p1)*c100 + dr_wet = S_wet * fliq**3*dt/(c4*pi*rsnw**2) + endif + + end subroutine snow_wet_metamorph + +!======================================================================= + +! Conversions between ice mass, liquid water mass in snow + + subroutine drain_snow (dt, nslyr, vsnon, aicen, & + smice, smliq, meltsliq) + + integer (kind=int_kind), intent(in) :: & + nslyr ! number of snow layers + + real (kind=dbl_kind), intent(in) :: & + dt, & ! time step + vsnon, & ! snow volume (m) + aicen ! aice area + + real (kind=dbl_kind), intent(inout) :: & + meltsliq ! total liquid content + + real (kind=dbl_kind), dimension(nslyr), & + intent(in) :: & + smice ! mass of ice in snow (kg/m^2) + + real (kind=dbl_kind), dimension(nslyr), & + intent(inout) :: & + smliq ! mass of liquid in snow (kg/m^2) + + ! local temporary variables + + integer (kind=int_kind) :: k + + real (kind=dbl_kind) :: & + hslyr, & ! snow layer thickness (m) + hsn ! snow thickness (m) + + real (kind=dbl_kind), dimension(nslyr) :: & + dlin , & ! liquid into the layer from above (kg/m^2) + dlout , & ! liquid out of the layer (kg/m^2) + phi_liq , & ! volumetric liquid fraction + phi_ice , & ! volumetric ice fraction + w_drain ! flow between layers + + character (len=*),parameter :: subname='(drain_snow)' + + hsn = c0 + if (aicen > c0) hsn = vsnon/aicen + if (hsn > puny) then + dlin(:) = c0 + dlout(:) = c0 + hslyr = hsn / real(nslyr,kind=dbl_kind) + meltsliq = c0 + do k = 1,nslyr + smliq(k) = smliq(k) + dlin(k) / hslyr ! liquid in from above layer + phi_ice(k) = min(c1, smice(k) / rhoi) + phi_liq(k) = smliq(k)/rhofresh + w_drain(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) / dt * rhofresh * hslyr) + dlout(k) = w_drain(k) * dt + smliq(k) = smliq(k) - dlout(k)/ hslyr + if (k < nslyr) then + dlin(k+1) = dlout(k) + else + meltsliq = dlout(nslyr) + endif + enddo + else + meltsliq = meltsliq ! computed in thickness_changes + endif + + end subroutine drain_snow + +!======================================================================= + + end module icepack_snow + +!======================================================================= diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 92a035037..ecf2b8130 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -61,7 +61,8 @@ module icepack_therm_vertical private public :: frzmlt_bottom_lateral, & thermo_vertical, & - icepack_step_therm1 + icepack_step_therm1, & + adjust_enthalpy !======================================================================= From 2f01d2d7c4dc2f7785b08f958150dbe70aff4631 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 4 Sep 2020 18:59:41 -0600 Subject: [PATCH 07/47] rename ice_snow.F90, add icepack_step_snow, call drain_snow, move adjust_enthalpy, add snowage parameters --- columnphysics/icepack_parameters.F90 | 59 +++- .../{ice_snow.F90 => icepack_snow.F90} | 308 ++++++++++++------ columnphysics/icepack_therm_shared.F90 | 88 ++++- columnphysics/icepack_therm_vertical.F90 | 139 +++----- 4 files changed, 398 insertions(+), 196 deletions(-) rename columnphysics/{ice_snow.F90 => icepack_snow.F90} (78%) diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index a9203a6f5..069ddf718 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -329,13 +329,26 @@ module icepack_parameters snwlvlfac = 0.3_dbl_kind ! fractional increase in snow ! depth for bulk redistribution + ! indices for aging lookup table [idx] + integer (kind=int_kind), public :: & + isnw_T = 11 , & ! maxiumum temperature index + isnw_Tgrd = 31 , & ! maxiumum temperature gradient index + isnw_rhos = 8 ! maxiumum snow density index + + ! dry snow aging parameters +! real (kind=dbl_kind), dimension(isnw_T,isnw_Tgrd,isnw_rhos), public :: & + real (kind=dbl_kind), dimension(11,31,8), public :: & + snowage_tau, & ! (10^-6 m) + snowage_kappa, & ! + snowage_drdt0 ! (10^-6 m/hr) + !----------------------------------------------------------------------- ! Parameters for biogeochemistry !----------------------------------------------------------------------- character(char_len), public :: & ! skl biology parameters - bgc_flux_type = 'Jin2006' ! type of ocean-ice poston velocity (or 'constant') + bgc_flux_type = 'Jin2006' ! type of ocean-ice piston velocity (or 'constant') logical (kind=log_kind), public :: & z_tracers = .false., & ! if .true., bgc or aerosol tracers are vertically resolved @@ -437,7 +450,8 @@ subroutine icepack_init_parameters( & sw_redist_in, sw_frac_in, sw_dtemp_in, & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & rhosnew_in, rhosmin_in, rhosmax_in, windmin_in, drhosdwind_in, & - snwlvlfac_in) + snwlvlfac_in, isnw_T_in, isnw_Tgrd_in, isnw_rhos_in, & + snowage_tau_in, snowage_kappa_in, snowage_drdt0_in) !----------------------------------------------------------------- ! parameter constants @@ -749,7 +763,15 @@ subroutine icepack_init_parameters( & rhosmax_in, & ! maximum snow density (kg/m^3) windmin_in, & ! minimum wind speed to compact snow (m/s) drhosdwind_in, & ! wind compaction factor (kg s/m^4) - snwlvlfac_in ! fractional increase in snow depth + snwlvlfac_in, & ! fractional increase in snow depth + isnw_T_in, & ! maxiumum temperature index + isnw_Tgrd_in, & ! maxiumum temperature gradient index + isnw_rhos_in ! maxiumum snow density index + + real (kind=dbl_kind), dimension(:,:,:), intent(in), optional :: & + snowage_tau_in, & ! (10^-6 m) + snowage_kappa_in, &! + snowage_drdt0_in ! (10^-6 m/hr) !autodocument_end @@ -874,6 +896,12 @@ subroutine icepack_init_parameters( & if (present(windmin_in) ) windmin = windmin_in if (present(drhosdwind_in) ) drhosdwind = drhosdwind_in if (present(snwlvlfac_in) ) snwlvlfac = snwlvlfac_in + if (present(isnw_T_in) ) isnw_T = isnw_T_in + if (present(isnw_Tgrd_in) ) isnw_Tgrd = isnw_Tgrd_in + if (present(isnw_rhos_in) ) isnw_rhos = isnw_rhos_in + if (present(snowage_tau_in) ) snowage_tau = snowage_tau_in + if (present(snowage_kappa_in) ) snowage_kappa = snowage_kappa_in + if (present(snowage_drdt0_in) ) snowage_drdt0 = snowage_drdt0_in if (present(bgc_flux_type_in) ) bgc_flux_type = bgc_flux_type_in if (present(z_tracers_in) ) z_tracers = z_tracers_in if (present(scale_bgc_in) ) scale_bgc = scale_bgc_in @@ -968,7 +996,8 @@ subroutine icepack_query_parameters( & sw_redist_out, sw_frac_out, sw_dtemp_out, & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & rhosnew_out, rhosmin_out, rhosmax_out, windmin_out, drhosdwind_out, & - snwlvlfac_out) + snwlvlfac_out, isnw_T_out, isnw_Tgrd_out, isnw_rhos_out, & + snowage_tau_out, snowage_kappa_out, snowage_drdt0_out) !----------------------------------------------------------------- ! parameter constants @@ -1289,7 +1318,15 @@ subroutine icepack_query_parameters( & rhosmax_out, & ! maximum snow density (kg/m^3) windmin_out, & ! minimum wind speed to compact snow (m/s) drhosdwind_out, & ! wind compaction factor (kg s/m^4) - snwlvlfac_out ! fractional increase in snow depth + snwlvlfac_out, & ! fractional increase in snow depth + isnw_T_out, & ! maxiumum temperature index + isnw_Tgrd_out, & ! maxiumum temperature gradient index + isnw_rhos_out ! maxiumum snow density index + + real (kind=dbl_kind), dimension(:,:,:), intent(out), optional :: & + snowage_tau_out, & ! (10^-6 m) + snowage_kappa_out, &! + snowage_drdt0_out ! (10^-6 m/hr) !autodocument_end character(len=*),parameter :: subname='(icepack_query_parameters)' @@ -1454,6 +1491,12 @@ subroutine icepack_query_parameters( & if (present(windmin_out) ) windmin_out = windmin if (present(drhosdwind_out) ) drhosdwind_out = drhosdwind if (present(snwlvlfac_out) ) snwlvlfac_out = snwlvlfac + if (present(isnw_T_out) ) isnw_T_out = isnw_T + if (present(isnw_Tgrd_out) ) isnw_Tgrd_out = isnw_Tgrd + if (present(isnw_rhos_out) ) isnw_rhos_out = isnw_rhos + if (present(snowage_tau_out) ) snowage_tau_out = snowage_tau + if (present(snowage_kappa_out) ) snowage_kappa_out= snowage_kappa + if (present(snowage_drdt0_out) ) snowage_drdt0_out= snowage_drdt0 if (present(bgc_flux_type_out) ) bgc_flux_type_out= bgc_flux_type if (present(z_tracers_out) ) z_tracers_out = z_tracers if (present(scale_bgc_out) ) scale_bgc_out = scale_bgc @@ -1642,6 +1685,12 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " windmin = ", windmin write(iounit,*) " drhosdwind = ", drhosdwind write(iounit,*) " snwlvlfac = ", snwlvlfac + write(iounit,*) " isnw_T = ", isnw_T + write(iounit,*) " isnw_Tgrd = ", isnw_Tgrd + write(iounit,*) " isnw_rhos = ", isnw_rhos + write(iounit,*) " snowage_tau = ", snowage_tau + write(iounit,*) " snowage_kappa = ", snowage_kappa + write(iounit,*) " snowage_drdt0 = ", snowage_drdt0 write(iounit,*) " bgc_flux_type = ", bgc_flux_type write(iounit,*) " z_tracers = ", z_tracers write(iounit,*) " scale_bgc = ", scale_bgc diff --git a/columnphysics/ice_snow.F90 b/columnphysics/icepack_snow.F90 similarity index 78% rename from columnphysics/ice_snow.F90 rename to columnphysics/icepack_snow.F90 index 5667d36df..f877daaa2 100644 --- a/columnphysics/ice_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -9,28 +9,176 @@ module icepack_snow use icepack_kinds use icepack_parameters, only: puny, p1, p5, c0, c1, c4, c10, c100, pi - use icepack_parameters, only: rhos, rhow, rhoi, rhofresh, rhosmin + use icepack_parameters, only: rhos, rhow, rhoi, rhofresh use icepack_parameters, only: snwlvlfac, Tffresh, cp_ice, Lfresh + use icepack_parameters, only: snwredist, rsnw_fall, rsnw_tmax, rhosnew + use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind + use icepack_parameters, only: isnw_T, isnw_Tgrd, isnw_rhos + use icepack_parameters, only: snowage_tau, snowage_kappa, snowage_drdt0 use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort implicit none private -! public :: snow_effective_density, update_snow_radius, snow_redist, & -! drain_snow + public :: drain_snow real (kind=dbl_kind), parameter, public :: & S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) S_wet= 0.422_dbl_kind ! (um^3/s) wet metamorphism parameters -! character(len=5), parameter, public :: & -! snwredist = 'ITDrdg' ! - !======================================================================= contains +!======================================================================= +! +! Updates snow tracers +! +! authors: Elizabeth C. Hunke, LANL +! Nicole Jeffery, LANL + + subroutine icepack_step_snow(dt, wind, & + nilyr, & + nslyr, ncat, & + aice, aicen, & + vicen, vsnon, & + alvl, vlvl, & + smice, smliq, & + rhos_effn, rhos_eff, & + rhos_cmpn, rhos_cmp, & + rsnw, zTin1, & + Tsfc, zqsn, & + fresh, fhocn, & + fsloss, fsnow) + + integer (kind=int_kind), intent(in) :: & + nslyr, & ! number of snow layers + nilyr, & ! number of ice layers + ncat ! number of thickness categories + + real (kind=dbl_kind), intent(in) :: & + dt , & ! time step + wind , & ! wind speed (m/s) + fsnow , & ! snowfall rate (kg m-2 s-1) + aice ! ice area fraction + + real (kind=dbl_kind), dimension(:), intent(in) :: & + aicen, & ! ice area fraction + vicen, & ! ice volume (m) + Tsfc , & ! surface temperature (C) + zTin1, & ! ice upper layer temperature + alvl, & ! level ice area tracer + vlvl ! level ice volume tracer + + real (kind=dbl_kind), intent(inout) :: & + fresh , & ! fresh water flux to ocean (kg/m^2/s) + fhocn , & ! net heat flux to ocean (W/m^2) + fsloss ! snow loss to leads (kg/m^2/s) + + real (kind=dbl_kind), dimension(:), intent(inout) :: & + vsnon ! snow volume (m) + + real (kind=dbl_kind), dimension(:,:), intent(inout) :: & + zqsn , & ! snow enthalpy (J/m^3) + smice , & ! mass of ice in snow (kg/m^3) + smliq , & ! mass of liquid in snow (kg/m^3) + rsnw , & ! snow grain radius (10^-6 m) + rhos_effn, & ! effective snow density: content (kg/m^3) + rhos_cmpn ! effective snow density: compaction (kg/m^3) + + real (kind=dbl_kind), intent(inout) :: & + rhos_eff , & ! mean effective snow density: content (kg/m^3) + rhos_cmp ! mean effective snow density: compaction (kg/m^3) + + ! local temporary variables + + integer (kind=int_kind) :: n + + real (kind=dbl_kind), dimension(ncat) :: & + zTin, & ! ice upper layer temperature (oC) + hsn , & ! snow thickness (m) + hin ! ice thickness + + real (kind=dbl_kind) :: & + vsno, & ! snow volume (m) + tmp1, tmp2 + + character (len=*),parameter :: subname='(icepack_step_snow)' + + !----------------------------------------------------------------- + ! Compute effective density of snow + !----------------------------------------------------------------- + + vsno = c0 + do n = 1, ncat + vsno = vsno + vsnon(n) + enddo + + call snow_effective_density(nslyr, ncat, & + vsnon, vsno, & + smice, smliq, & + rhos_effn, rhos_eff, & + rhos_cmpn, rhos_cmp) + + !----------------------------------------------------------------- + ! Redistribute snow based on wind + !----------------------------------------------------------------- + + tmp1 = rhos*vsno + fresh*dt + + if (snwredist(1:3) == 'ITD' .and. aice > puny) then + call snow_redist(dt, & + nslyr, ncat, & + wind, aicen(:), & + vicen(:), vsnon(:), & + zqsn(:,:), & + alvl(:), vlvl(:), & + fresh, fhocn, & + fsloss, rhos_cmpn, & + fsnow) + endif + + vsno = c0 + do n = 1, ncat + vsno = vsno + vsnon(n) + enddo + tmp2 = rhos*vsno + fresh*dt + + ! check conservation +! if (abs(tmp1-tmp2)>puny) then +! write(warning,*) ' ' +! call add_warning(warning) +! write(warning,*)'tmp1 ne tmp2',tmp1, tmp2 +! call add_warning(warning) +! stop_label ='snow redistribution error' +! l_stop = .true. +! endif + + !----------------------------------------------------------------- + ! Adjust snow grain radius + !----------------------------------------------------------------- + + do n = 1, ncat + zTin(n)= c0 + hsn(n) = c0 + hin(n) = c0 + if (aicen(n) > puny) then +!ech move up zTin(n) = colpkg_ice_temperature(zqin1(n),zSin1(n)) + hsn(n) = vsnon(n)/aicen(n) + hin(n) = vicen(n)/aicen(n) + endif + enddo + + call update_snow_radius (dt, ncat, & + nslyr, nilyr, & + rsnw, hin, & + Tsfc, zTin, & + hsn, zqsn, & + smice, smliq) + + end subroutine icepack_step_snow + !======================================================================= ! Compute effective density of snow layers from ice, liquid water mass @@ -38,7 +186,6 @@ module icepack_snow subroutine snow_effective_density(nslyr, ncat, & vsnon, vsno, & smice, smliq, & - rhosnew, & rhos_effn, rhos_eff, & rhos_cmpn, rhos_cmp) @@ -50,8 +197,7 @@ subroutine snow_effective_density(nslyr, ncat, & vsnon ! snow volume (m) real (kind=dbl_kind), intent(in) :: & - vsno , & ! total snow volume (m) - rhosnew ! new snow density (kg/m^3) + vsno ! total snow volume (m) real (kind=dbl_kind), dimension(:,:), & intent(inout) :: & @@ -125,10 +271,9 @@ end subroutine snow_effective_density ! thickness does not subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & - snwredist, alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, & - fsnow, rhosmax, windmin, drhosdwind) + alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, fsnow) - use icepack_therm_vertical, only: adjust_enthalpy + use icepack_therm_shared, only: adjust_enthalpy integer (kind=int_kind), intent(in) :: & nslyr , & ! number of snow layers @@ -137,10 +282,7 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & real (kind=dbl_kind), intent(in) :: & dt , & ! time step (s) wind , & ! wind speed (m/s) - fsnow , & ! snowfall rate (kg m-2 s-1) - rhosmax , & ! maximum snow density (kg/m^3) - windmin , & ! minimum wind speed to compact snow (m/s) - drhosdwind ! wind compaction factor (kg s/m^4) + fsnow ! snowfall rate (kg m-2 s-1) real (kind=dbl_kind), dimension(:), intent(in) :: & ain , & ! ice area fraction @@ -160,9 +302,6 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & zqsn , & ! snow enthalpy (J/m^3) rhos_cmpn ! effective snow density: compaction (kg/m^3) - character(len=char_len), intent(in) :: & - snwredist ! type of snow redistribution - ! local variables integer (kind=int_kind) :: & @@ -555,26 +694,15 @@ end subroutine snow_redist !======================================================================= -! Snow grain metamorphism driver +! Snow grain metamorphism subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & - Tsfc, zTin, & - hsn, zqsn, smice, smliq, & - rsnw_fall, rsnw_tmax, & - snowage_tau, & - snowage_kappa, & - snowage_drdt0, & - idx_T_max, & - idx_Tgrd_max, & - idx_rhos_max) + Tsfc, zTin, hsn, zqsn, smice, smliq) integer (kind=int_kind), intent(in) :: & ncat, & ! number of categories nslyr, & ! number of snow layers - nilyr, & ! number of ice layers - idx_T_max, & ! dimensions of snow parameter matrix - idx_Tgrd_max, & - idx_rhos_max + nilyr ! number of ice layers real (kind=dbl_kind), intent(in) :: & dt ! time step @@ -589,23 +717,12 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & zqsn ! enthalpy of snow (J m-3) real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: & - rsnw + rsnw ! snow grain radius - real (kind=dbl_kind), dimension(nslyr,ncat), & - intent(inout) :: & + real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: & smice, & ! mass of ice in snow (kg/m^2) smliq ! mass of liquid in snow (kg/m^2) - real (kind=dbl_kind), intent(in) :: & - rsnw_fall, & ! radius of newly fallen snow (10^-6 m) - rsnw_tmax ! maximum grain radius from dry metamorphism (10^-6 m) - - ! dry snow aging parameters - real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: & - snowage_tau, & ! (10^-6 m) - snowage_kappa, & ! - snowage_drdt0 ! (10^-6 m/hr) - ! local temporary variables integer (kind=int_kind) :: k, n @@ -626,12 +743,11 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & !----------------------------------------------------------------- ! dry metamorphism !----------------------------------------------------------------- - call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & - drsnw_dry, zqsn(:,n), Tsfc(n), & - zTin(n), hsn(n), hin(n), & - smice(:,n), smliq(:,n), rsnw_fall, & - snowage_tau, snowage_kappa, snowage_drdt0, & - idx_T_max, idx_Tgrd_max, idx_rhos_max) +!echmod - data for table can not be read by Icepack +! call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & +! drsnw_dry, zqsn(:,n), Tsfc(n), & +! zTin(n), hsn(n), hin(n), & +! smice(:,n), smliq(:,n)) !----------------------------------------------------------------- ! wet metamorphism @@ -644,8 +760,8 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & else do k = 1,nslyr - ! rsnw_fall < rsnw < rsnw_tmax - rsnw(k,n) = max(rsnw_fall,min(rsnw_tmax, rsnw(k,n))) + ! rsnw_fall < rsnw < rsnw_tmax + rsnw (k,n) = max(rsnw_fall, min(rsnw_tmax, rsnw(k,n))) smice(k,n) = rhos smliq(k,n) = c0 enddo @@ -659,11 +775,9 @@ end subroutine update_snow_radius ! Snow grain metamorphism subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & - Tsfc, zTin1, hsn, hin, smice, smliq, rsnw_fall, & - snowage_tau, snowage_kappa, snowage_drdt0, & - idx_T_max, idx_Tgrd_max, idx_rhos_max) + Tsfc, zTin1, hsn, hin, smice, smliq) - ! Vapor redistribution: Method is to retrieve 3 best-bit parameters that + ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that ! depend on snow temperature, temperature gradient, and density, ! that are derived from the microphysical model described in: ! Flanner and Zender (2006), Linking snowpack microphysics and albedo @@ -674,14 +788,11 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & ! tau and kappa are best-fit parameters, ! drdt_0 is the initial rate of change of effective radius, and ! dr_fresh is the difference between the current and fresh snow states - ! (r_current - r_fresh). + ! (r_current - r_fresh). integer (kind=int_kind), intent(in) :: & nslyr, & ! number of snow layers - nilyr, & ! number of ice layers - idx_T_max, & ! dimensions of snow parameter matrix - idx_Tgrd_max, & - idx_rhos_max + nilyr ! number of ice layers real (kind=dbl_kind), intent(in) :: & dt ! time step (s) @@ -698,31 +809,24 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & drsnw_dry ! change due to snow aging (10^-6 m) real (kind=dbl_kind), intent(in) :: & - Tsfc, & ! surface temperature (oC) - zTin1, & ! top ice layer temperature (oC) + Tsfc, & ! surface temperature (C) + zTin1, & ! top ice layer temperature (C) hsn, & ! snow thickness (m) - hin, & ! ice thickness (m) - rsnw_fall - - ! dry snow aging parameters - real (kind=dbl_kind), dimension(idx_rhos_max,idx_Tgrd_max,idx_T_max), intent(in) :: & - snowage_tau, & ! (10^-6 m) - snowage_kappa, & ! - snowage_drdt0 ! (10^-6 m/hr) + hin ! ice thickness (m) ! local temporary variables integer (kind=int_kind) :: k integer (kind=int_kind) :: & - T_idx, & ! temperature index - Tgrd_idx, & ! temperature gradient index - rhos_idx ! density index + T_idx, & ! temperature index + Tgrd_idx, & ! temperature gradient index + rhos_idx ! density index real (kind=dbl_kind), dimension(nslyr):: & zrhos, & ! snow density (kg/m^3) ! for variable snow density zdTdz, & ! temperature gradient (K/s) - zTsn ! snow temperature (oC) + zTsn ! snow temperature (C) real (kind=dbl_kind) :: & bst_tau, & ! snow aging parameter retrieved from lookup table [hour] @@ -730,7 +834,8 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & bst_drdt0, & ! snow aging parameter retrieved from lookup table [um hr-1] dr_fresh, & ! change in snow radius from fresh (10^-6 m) dzs, & ! snow layer thickness (m) - dzi ! ice layer thickness (m) + dzi, & ! ice layer thickness (m) + dz ! dzs + dzi (m) character (len=*),parameter :: subname='(snow_dry_metamorph)' @@ -744,29 +849,32 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & dzs = hsn/real(nslyr,kind=dbl_kind) dzi = hin/real(nilyr,kind=dbl_kind) + dz = dzs + dzi zTsn(1) = (Lfresh + zqsn(1)/rhos)/cp_ice if (nslyr == 1) then - zdTdz(1) = min(c10*idx_Tgrd_max, & - abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny)) + + zdTdz(1) = min(c10*isnw_Tgrd, & +!ech refactored abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny)) + abs(zTsn(1)*dzi + zTin1*dzs - Tsfc*dz)/(dz*hsn+puny)) else - zTsn(1) =(Lfresh + zqsn(1)/rhos)/cp_ice -!ech fix this loop - remove if/else/endif - do k = 2, nslyr - zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice - if (k == 2) then - zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny) - zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1)) - else - zdTdz(k-1) = abs(zTsn(k-2)-zTsn(k))*p5/(dzs+puny) - zdTdz(k-1) = min(c10*idx_Tgrd_max,zdTdz(k-1)) - endif - enddo - zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) & - - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny) - zdTdz(nslyr) = min(c10*idx_Tgrd_max, zdTdz(nslyr)) + do k = 2, nslyr + zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice + if (k == 2) then + zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny) + else + zdTdz(k-1) = abs (zTsn(k-2)-zTsn(k))*p5 /(dzs+puny) + endif + zdTdz(k-1) = min(c10*isnw_Tgrd,zdTdz(k-1)) + enddo +!ech refactored zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) & +!ech refactored - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny) + zdTdz(nslyr) = p5*abs((zTin1-zTsn(nslyr))/(dz+puny) - zTsn(nslyr-1)/(dzs+puny)) + zdTdz(nslyr) = min(c10*isnw_Tgrd, zdTdz(nslyr)) endif +!echmod - table will not be available in Icepack standalone (netcdf) + ! best-fit parameters are read from a table ! 11 temperatures from 225 to 273 K ! 31 temperature gradients from 0 to 300 K/m @@ -776,18 +884,18 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & do k = 1, nslyr zrhos(k) = smice(k) + smliq(k) - ! best-fit table indecies: + ! best-fit table indices: T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind) Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind) !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! variable density rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! fixed density ! boundary check: - T_idx = min(idx_T_max, max(1,T_idx+1))!min(idx_T_max, max(idx_T_min,T_idx)) - Tgrd_idx = min(idx_Tgrd_max, max(1,Tgrd_idx+1))!min(idx_Tgrd_max, max(idx_Tgrd_min,Tgrd_idx)) - rhos_idx = min(idx_rhos_max, max(1,rhos_idx+1)) !min(idx_rhos_max, max(idx_rhos_min,rhos_idx)) + T_idx = min(isnw_T, max(1,T_idx+1)) + Tgrd_idx = min(isnw_Tgrd, max(1,Tgrd_idx+1)) + rhos_idx = min(isnw_rhos, max(1,rhos_idx+1)) - bst_tau = snowage_tau(rhos_idx,Tgrd_idx,T_idx) + bst_tau = snowage_tau (rhos_idx,Tgrd_idx,T_idx) bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx) bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx) diff --git a/columnphysics/icepack_therm_shared.F90 b/columnphysics/icepack_therm_shared.F90 index 1448d0896..16fab1c16 100644 --- a/columnphysics/icepack_therm_shared.F90 +++ b/columnphysics/icepack_therm_shared.F90 @@ -8,7 +8,7 @@ module icepack_therm_shared use icepack_kinds - use icepack_parameters, only: c0, c1, c2, c4, p5, pi + use icepack_parameters, only: c0, c1, c2, c4, p5, pi, puny use icepack_parameters, only: cp_ocn, cp_ice, rhoi, rhos, Tffresh, TTTice, qqqice use icepack_parameters, only: stefan_boltzmann, emissivity, Lfresh, Tsmelt use icepack_parameters, only: saltmax, min_salin, depressT @@ -35,7 +35,8 @@ module icepack_therm_shared icepack_snow_temperature, & icepack_liquidus_temperature, & icepack_sea_freezing_temperature, & - icepack_enthalpy_snow + icepack_enthalpy_snow, & + adjust_enthalpy real (kind=dbl_kind), parameter, public :: & ferrmax = 1.0e-3_dbl_kind ! max allowed energy flux error (W m-2) @@ -476,6 +477,89 @@ function icepack_enthalpy_snow(zTsn) result(qsn) end function icepack_enthalpy_snow +!======================================================================= +! +! Conserving energy, compute the new enthalpy of equal-thickness ice +! or snow layers. +! +! authors William H. Lipscomb, LANL +! C. M. Bitz, UW + + subroutine adjust_enthalpy (nlyr, & + z1, z2, & + hlyr, hn, & + qn) + + integer (kind=int_kind), intent(in) :: & + nlyr ! number of layers (nilyr or nslyr) + + real (kind=dbl_kind), dimension (:), intent(in) :: & + z1 , & ! interface depth for old, unequal layers (m) + z2 ! interface depth for new, equal layers (m) + + real (kind=dbl_kind), intent(in) :: & + hlyr ! new layer thickness (m) + + real (kind=dbl_kind), intent(in) :: & + hn ! total thickness (m) + + real (kind=dbl_kind), dimension (:), intent(inout) :: & + qn ! layer quantity (enthalpy, salinity...) + + ! local variables + + integer (kind=int_kind) :: & + k, k1, k2 ! vertical indices + + real (kind=dbl_kind) :: & + hovlp ! overlap between old and new layers (m) + + real (kind=dbl_kind) :: & + rhlyr ! 1./hlyr + + real (kind=dbl_kind), dimension (nlyr) :: & + hq ! h * q for a layer + + character(len=*),parameter :: subname='(adjust_enthalpy)' + + !----------------------------------------------------------------- + ! Compute reciprocal layer thickness. + !----------------------------------------------------------------- + + rhlyr = c0 + if (hn > puny) rhlyr = c1 / hlyr + + !----------------------------------------------------------------- + ! Compute h*q for new layers (k2) given overlap with old layers (k1) + !----------------------------------------------------------------- + + do k2 = 1, nlyr + hq(k2) = c0 + enddo ! k + k1 = 1 + k2 = 1 + do while (k1 <= nlyr .and. k2 <= nlyr) + hovlp = min (z1(k1+1), z2(k2+1)) & + - max (z1(k1), z2(k2)) + hovlp = max (hovlp, c0) + hq(k2) = hq(k2) + hovlp*qn(k1) + if (z1(k1+1) > z2(k2+1)) then + k2 = k2 + 1 + else + k1 = k1 + 1 + endif + enddo ! while + + !----------------------------------------------------------------- + ! Compute new enthalpies. + !----------------------------------------------------------------- + + do k = 1, nlyr + qn(k) = hq(k) * rhlyr + enddo ! k + + end subroutine adjust_enthalpy + !======================================================================= end module icepack_therm_shared diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index ecf2b8130..e65e7546c 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -26,7 +26,7 @@ module icepack_therm_vertical use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair use icepack_parameters, only: rfracmin, rfracmax, pndaspect, dpscale, frzpnd - use icepack_parameters, only: phi_i_mushy + use icepack_parameters, only: phi_i_mushy, use_smliq_pnd use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo @@ -35,6 +35,7 @@ module icepack_therm_vertical use icepack_therm_shared, only: ferrmax, l_brine use icepack_therm_shared, only: calculate_tin_from_qin, Tmin use icepack_therm_shared, only: hi_min + use icepack_therm_shared, only: adjust_enthalpy use icepack_therm_bl99, only: temperature_changes use icepack_therm_0layer, only: zerolayer_temperature use icepack_therm_mushy, only: temperature_changes_salinity @@ -55,14 +56,14 @@ module icepack_therm_vertical use icepack_meltpond_cesm, only: compute_ponds_cesm use icepack_meltpond_lvl, only: compute_ponds_lvl use icepack_meltpond_topo, only: compute_ponds_topo + use icepack_snow, only: drain_snow implicit none private public :: frzmlt_bottom_lateral, & thermo_vertical, & - icepack_step_therm1, & - adjust_enthalpy + icepack_step_therm1 !======================================================================= @@ -1747,89 +1748,6 @@ subroutine freeboard (nslyr, & end subroutine freeboard -!======================================================================= -! -! Conserving energy, compute the new enthalpy of equal-thickness ice -! or snow layers. -! -! authors William H. Lipscomb, LANL -! C. M. Bitz, UW - - subroutine adjust_enthalpy (nlyr, & - z1, z2, & - hlyr, hn, & - qn) - - integer (kind=int_kind), intent(in) :: & - nlyr ! number of layers (nilyr or nslyr) - - real (kind=dbl_kind), dimension (:), intent(in) :: & - z1 , & ! interface depth for old, unequal layers (m) - z2 ! interface depth for new, equal layers (m) - - real (kind=dbl_kind), intent(in) :: & - hlyr ! new layer thickness (m) - - real (kind=dbl_kind), intent(in) :: & - hn ! total thickness (m) - - real (kind=dbl_kind), dimension (:), intent(inout) :: & - qn ! layer quantity (enthalpy, salinity...) - - ! local variables - - integer (kind=int_kind) :: & - k, k1, k2 ! vertical indices - - real (kind=dbl_kind) :: & - hovlp ! overlap between old and new layers (m) - - real (kind=dbl_kind) :: & - rhlyr ! 1./hlyr - - real (kind=dbl_kind), dimension (nlyr) :: & - hq ! h * q for a layer - - character(len=*),parameter :: subname='(adjust_enthalpy)' - - !----------------------------------------------------------------- - ! Compute reciprocal layer thickness. - !----------------------------------------------------------------- - - rhlyr = c0 - if (hn > puny) rhlyr = c1 / hlyr - - !----------------------------------------------------------------- - ! Compute h*q for new layers (k2) given overlap with old layers (k1) - !----------------------------------------------------------------- - - do k2 = 1, nlyr - hq(k2) = c0 - enddo ! k - k1 = 1 - k2 = 1 - do while (k1 <= nlyr .and. k2 <= nlyr) - hovlp = min (z1(k1+1), z2(k2+1)) & - - max (z1(k1), z2(k2)) - hovlp = max (hovlp, c0) - hq(k2) = hq(k2) + hovlp*qn(k1) - if (z1(k1+1) > z2(k2+1)) then - k2 = k2 + 1 - else - k1 = k1 + 1 - endif - enddo ! while - - !----------------------------------------------------------------- - ! Compute new enthalpies. - !----------------------------------------------------------------- - - do k = 1, nlyr - qn(k) = hq(k) * rhlyr - enddo ! k - - end subroutine adjust_enthalpy - !======================================================================= ! ! Check for energy conservation by comparing the change in energy @@ -2111,7 +2029,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & melts , meltsn , & congel , congeln , & snoice , snoicen , & - dsnown , & + dsnown , meltsliqn , & + smicen , smliqn , & lmask_n , lmask_s , & mlt_onset , frz_onset , & yday , prescribed_ice) @@ -2219,7 +2138,12 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & Qref_iso , & ! isotope 2m atm reference spec humidity (kg/kg) fiso_atm , & ! isotope deposition rate (kg/m^2 s) fiso_ocn , & ! isotope flux to ocean (kg/m^2/s) - fiso_evap ! isotope evaporation (kg/m^2/s) + fiso_evap , & ! isotope evaporation (kg/m^2/s) + meltsliqn ! mass of snow melt (kg/m^2) + + real (kind=dbl_kind), dimension(:,:), optional, intent(inout) :: & + smicen , & ! mass of ice in snow (kg/m^2) + smliqn ! mass of liquid in snow (kg/m^2) real (kind=dbl_kind), optional, intent(in) :: & HDO_ocn , & ! ocean concentration of HDO (kg/kg) @@ -2328,7 +2252,12 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_Qref_iso , & ! local isotope 2m atm reference spec humidity (kg/kg) l_fiso_atm , & ! local isotope deposition rate (kg/m^2 s) l_fiso_ocn , & ! local isotope flux to ocean (kg/m^2/s) - l_fiso_evap ! local isotope evaporation (kg/m^2/s) + l_fiso_evap , & ! local isotope evaporation (kg/m^2/s) + l_meltsliq ! mass of snow melt (kg/m^2) + + real (kind=dbl_kind), allocatable, dimension(:,:) :: & + l_smice , & ! mass of ice in snow (kg/m^2) + l_smliq ! mass of liquid in snow (kg/m^2) real (kind=dbl_kind) :: & l_HDO_ocn , & ! local ocean concentration of HDO (kg/kg) @@ -2450,6 +2379,31 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_fswthrun_idf = c0 if (present(fswthrun_idf) ) l_fswthrun_idf = fswthrun_idf +!echmod: make a subroutine to do this for each array? + if (present(meltsliqn) ) then + allocate(l_meltsliq(size(meltsliqn))) + l_meltsliq = meltsliqn + else + allocate(l_meltsliq(1)) + l_meltsliq = c0 + endif + + if (present(smicen) ) then + allocate(l_smice(size(smicen,dim=1),size(smicen,dim=2))) + l_smice = smicen + else + allocate(l_smice(1,1)) + l_smice = c0 + endif + + if (present(smliqn) ) then + allocate(l_smliq(size(smliqn,dim=1),size(smliqn,dim=2))) + l_smliq = smliqn + else + allocate(l_smliq(1,1)) + l_smliq = c0 + endif + !----------------------------------------------------------------- ! Adjust frzmlt to account for ice-ocean heat fluxes since last ! call to coupler. @@ -2676,6 +2630,13 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & endif endif ! aicen_init + if (use_smliq_pnd) then !echmod make sure tr_snow=T too + call drain_snow (dt = dt, nslyr = nslyr, & + vsnon = vsnon(n), aicen = aicen(n), & + smice = smicen(:,n), smliq = smliqn(:,n), & + meltsliq = meltsliqn(n)) + endif + !----------------------------------------------------------------- ! Melt ponds ! If using tr_pond_cesm, the full calculation is performed here. From ee5d2c0918ce5062d3159458a264a2f4c03d55c9 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 19 Feb 2021 09:32:01 -0700 Subject: [PATCH 08/47] bug fix: dsnow was not being aggregated from category values --- columnphysics/icepack_flux.F90 | 5 ++++- columnphysics/icepack_therm_vertical.F90 | 11 +++++++---- configuration/driver/icedrv_step.F90 | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/columnphysics/icepack_flux.F90 b/columnphysics/icepack_flux.F90 index a1029379a..281d87e48 100644 --- a/columnphysics/icepack_flux.F90 +++ b/columnphysics/icepack_flux.F90 @@ -58,7 +58,7 @@ subroutine merge_fluxes (aicen, & fswthru_idr, fswthru_idf,& melttn, meltsn, meltbn, congeln, snoicen, & meltt, melts, & - meltb, & + meltb, dsnow, dsnown,& congel, snoice, & Uref, Urefn, & Qref_iso, Qrefn_iso, & @@ -95,6 +95,7 @@ subroutine merge_fluxes (aicen, & melttn , & ! top ice melt (m) meltbn , & ! bottom ice melt (m) meltsn , & ! snow melt (m) + dsnown , & ! change in snow depth (m) congeln , & ! congelation ice growth (m) snoicen ! snow-ice growth (m) @@ -125,6 +126,7 @@ subroutine merge_fluxes (aicen, & meltt , & ! top ice melt (m) meltb , & ! bottom ice melt (m) melts , & ! snow melt (m) + dsnow , & ! change in snow depth (m) congel , & ! congelation ice growth (m) snoice ! snow-ice growth (m) @@ -212,6 +214,7 @@ subroutine merge_fluxes (aicen, & meltt = meltt + melttn * aicen meltb = meltb + meltbn * aicen melts = melts + meltsn * aicen + dsnow = dsnow + dsnown * aicen congel = congel + congeln * aicen snoice = snoice + snoicen * aicen diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 756bb0e1f..e38ba7306 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2027,7 +2027,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & melts , meltsn , & congel , congeln , & snoice , snoicen , & - dsnown , meltsliqn , & + dsnow , dsnown , & + meltsliqn , & smicen , smliqn , & lmask_n , lmask_s , & mlt_onset , frz_onset , & @@ -2122,6 +2123,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & meltt , & ! top ice melt (m/step-->cm/day) melts , & ! snow melt (m/step-->cm/day) meltb , & ! basal ice melt (m/step-->cm/day) + dsnow , & ! change in snow depth (m/step-->cm/day) mlt_onset , & ! day of year that sfc melting begins frz_onset ! day of year that freezing begins (congel or frazil) @@ -2740,9 +2742,10 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fswthru_idf=l_fswthru_idf, & melttn=melttn (n), meltsn=meltsn(n), & meltbn=meltbn (n), congeln=congeln(n),& - snoicen=snoicen(n), & meltt=meltt, melts=melts, & - meltb=meltb, congel=congel, & + meltb=meltb, snoicen=snoicen(n),& + dsnow=dsnow, dsnown=dsnown(n), & + congel=congel, & snoice=snoice, & Uref=Uref, Urefn=Urefn, & Qref_iso=l_Qref_iso, & @@ -2751,7 +2754,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fiso_ocnn=fiso_ocnn, & fiso_evap=l_fiso_evap, & fiso_evapn=fiso_evapn) - +if (snoice > puny) print*,'snoice',snoice if (icepack_warnings_aborted(subname)) return enddo ! ncat diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 7d6b68c70..82f5f5ebc 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -123,7 +123,7 @@ subroutine step_therm1 (dt) use icedrv_flux, only: meltt, melts, meltb, congel, snoice use icedrv_flux, only: fswthru, fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf use icedrv_flux, only: flatn_f, fsensn_f, fsurfn_f, fcondtopn_f - use icedrv_flux, only: dsnown, faero_atm, faero_ocn + use icedrv_flux, only: dsnow, dsnown, faero_atm, faero_ocn use icedrv_flux, only: fiso_atm, fiso_ocn, fiso_evap use icedrv_flux, only: HDO_ocn, H2_16O_ocn, H2_18O_ocn use icedrv_init, only: lmask_n, lmask_s @@ -346,7 +346,7 @@ subroutine step_therm1 (dt) melts = melts(i), meltsn = meltsn(i,:), & congel = congel(i), congeln = congeln(i,:), & snoice = snoice(i), snoicen = snoicen(i,:), & - dsnown = dsnown(i,:), & + dsnow = dsnow(i), dsnown = dsnown(i,:), & lmask_n = lmask_n(i), lmask_s = lmask_s(i), & mlt_onset=mlt_onset(i), frz_onset = frz_onset(i), & yday = yday, prescribed_ice = prescribed_ice) From a785e1069e80be4cb4ed36ca19dc7f4e4b62c906 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 19 Feb 2021 15:26:48 -0700 Subject: [PATCH 09/47] add calls to new snow physics routines --- columnphysics/icepack_intfc.F90 | 2 + columnphysics/icepack_snow.F90 | 56 +++++++------ columnphysics/icepack_therm_vertical.F90 | 2 +- configuration/driver/icedrv_RunMod.F90 | 15 +++- configuration/driver/icedrv_arrays_column.F90 | 6 ++ configuration/driver/icedrv_flux.F90 | 1 + configuration/driver/icedrv_step.F90 | 78 ++++++++++++++++++- 7 files changed, 130 insertions(+), 30 deletions(-) diff --git a/columnphysics/icepack_intfc.F90 b/columnphysics/icepack_intfc.F90 index f6ce6f494..dd1fd1131 100644 --- a/columnphysics/icepack_intfc.F90 +++ b/columnphysics/icepack_intfc.F90 @@ -82,6 +82,8 @@ module icepack_intfc use icepack_wavefracspec, only: icepack_init_wave use icepack_wavefracspec, only: icepack_step_wavefracture + use icepack_snow, only: icepack_step_snow + use icepack_shortwave, only: icepack_prep_radiation use icepack_shortwave, only: icepack_step_radiation diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index f877daaa2..cb3fb9577 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -21,7 +21,7 @@ module icepack_snow implicit none private - public :: drain_snow + public :: icepack_step_snow, drain_snow real (kind=dbl_kind), parameter, public :: & S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) @@ -32,26 +32,29 @@ module icepack_snow contains !======================================================================= -! +!autodocument_start icepack_step_snow ! Updates snow tracers ! ! authors: Elizabeth C. Hunke, LANL ! Nicole Jeffery, LANL - subroutine icepack_step_snow(dt, wind, & - nilyr, & - nslyr, ncat, & - aice, aicen, & - vicen, vsnon, & - alvl, vlvl, & - smice, smliq, & - rhos_effn, rhos_eff, & - rhos_cmpn, rhos_cmp, & - rsnw, zTin1, & - Tsfc, zqsn, & - fresh, fhocn, & + subroutine icepack_step_snow(dt, nilyr, & + nslyr, ncat, & + wind, aice, & + aicen, vicen, & + vsnon, Tsfc, & + zqin1, zSin1, & + zqsn, & + alvl, vlvl, & + smice, smliq, & + rhos_cmpn, rsnw, & + rhos_eff, rhos_effn, & + rhos_cmp, & + fresh, fhocn, & fsloss, fsnow) + use icepack_therm_shared, only: icepack_ice_temperature + integer (kind=int_kind), intent(in) :: & nslyr, & ! number of snow layers nilyr, & ! number of ice layers @@ -67,7 +70,8 @@ subroutine icepack_step_snow(dt, wind, & aicen, & ! ice area fraction vicen, & ! ice volume (m) Tsfc , & ! surface temperature (C) - zTin1, & ! ice upper layer temperature + zqin1, & ! ice upper layer enthalpy + zSin1, & ! ice upper layer salinity alvl, & ! level ice area tracer vlvl ! level ice volume tracer @@ -91,13 +95,15 @@ subroutine icepack_step_snow(dt, wind, & rhos_eff , & ! mean effective snow density: content (kg/m^3) rhos_cmp ! mean effective snow density: compaction (kg/m^3) - ! local temporary variables +!autodocument_end + + ! local variables integer (kind=int_kind) :: n real (kind=dbl_kind), dimension(ncat) :: & - zTin, & ! ice upper layer temperature (oC) - hsn , & ! snow thickness (m) + zTin1, & ! ice upper layer temperature (C) + hsn , & ! snow thickness (m) hin ! ice thickness real (kind=dbl_kind) :: & @@ -160,20 +166,20 @@ subroutine icepack_step_snow(dt, wind, & !----------------------------------------------------------------- do n = 1, ncat - zTin(n)= c0 - hsn(n) = c0 - hin(n) = c0 + zTin1(n) = c0 + hsn (n) = c0 + hin (n) = c0 if (aicen(n) > puny) then -!ech move up zTin(n) = colpkg_ice_temperature(zqin1(n),zSin1(n)) - hsn(n) = vsnon(n)/aicen(n) - hin(n) = vicen(n)/aicen(n) + zTin1(n) = icepack_ice_temperature(zqin1(n), zSin1(n)) + hsn(n) = vsnon(n)/aicen(n) + hin(n) = vicen(n)/aicen(n) endif enddo call update_snow_radius (dt, ncat, & nslyr, nilyr, & rsnw, hin, & - Tsfc, zTin, & + Tsfc, zTin1, & hsn, zqsn, & smice, smliq) diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index e38ba7306..8fa32f970 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2754,7 +2754,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fiso_ocnn=fiso_ocnn, & fiso_evap=l_fiso_evap, & fiso_evapn=fiso_evapn) -if (snoice > puny) print*,'snoice',snoice + if (icepack_warnings_aborted(subname)) return enddo ! ncat diff --git a/configuration/driver/icedrv_RunMod.F90 b/configuration/driver/icedrv_RunMod.F90 index 2687f3a61..fda20a6ef 100644 --- a/configuration/driver/icedrv_RunMod.F90 +++ b/configuration/driver/icedrv_RunMod.F90 @@ -100,7 +100,7 @@ subroutine ice_step use icedrv_restart, only: dumpfile, final_restart use icedrv_restart_bgc, only: write_restart_bgc use icedrv_step, only: prep_radiation, step_therm1, step_therm2, & - update_state, step_dyn_ridge, step_radiation, & + update_state, step_dyn_ridge, step_snow, step_radiation, & biogeochemistry, step_dyn_wave integer (kind=int_kind) :: & @@ -108,7 +108,7 @@ subroutine ice_step logical (kind=log_kind) :: & calc_Tsfc, skl_bgc, solve_zsal, z_tracers, tr_brine, & ! from icepack - tr_fsd, wave_spec + tr_fsd, wave_spec, tr_snow real (kind=dbl_kind) :: & offset ! d(age)/dt time offset @@ -125,7 +125,8 @@ subroutine ice_step call icepack_query_parameters(solve_zsal_out=solve_zsal, & calc_Tsfc_out=calc_Tsfc, & wave_spec_out=wave_spec) - call icepack_query_tracer_flags(tr_brine_out=tr_brine,tr_fsd_out=tr_fsd) + call icepack_query_tracer_flags(tr_brine_out=tr_brine,tr_fsd_out=tr_fsd, & + tr_snow_out=tr_snow) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) @@ -183,6 +184,14 @@ subroutine ice_step ! call icedrv_diagnostics_debug ('post dynamics') + !----------------------------------------------------------------- + ! snow redistribution and metamorphosis + !----------------------------------------------------------------- + + if (tr_snow) call step_snow (dt) + +! call icedrv_diagnostics_debug ('post snow redistribution') + !----------------------------------------------------------------- ! albedo, shortwave radiation !----------------------------------------------------------------- diff --git a/configuration/driver/icedrv_arrays_column.F90 b/configuration/driver/icedrv_arrays_column.F90 index 870a25056..db52df2a0 100644 --- a/configuration/driver/icedrv_arrays_column.F90 +++ b/configuration/driver/icedrv_arrays_column.F90 @@ -62,6 +62,12 @@ module icedrv_arrays_column character (len=35), public :: c_hi_range(ncat) + ! icepack_snow.F90 + real (kind=dbl_kind), public, & + dimension (nx) :: & + rhos_eff , & ! mean effective snow density: content (kg/m^3) + rhos_cmp ! mean effective snow density: compaction (kg/m^3) + ! icepack_meltpond_lvl.F90 real (kind=dbl_kind), public, & dimension (nx, ncat) :: & diff --git a/configuration/driver/icedrv_flux.F90 b/configuration/driver/icedrv_flux.F90 index cfa395fb6..9b3a3d32b 100644 --- a/configuration/driver/icedrv_flux.F90 +++ b/configuration/driver/icedrv_flux.F90 @@ -178,6 +178,7 @@ module icedrv_flux fresh , & ! fresh water flux to ocean (kg/m^2/s) fsalt , & ! salt flux to ocean (kg/m^2/s) fhocn , & ! net heat flux to ocean (W/m^2) + fsloss , & ! snow loss to ocean due to wind redistribution (kg/m^2 s) fswthru , & ! shortwave penetrating to ocean (W/m^2) fswthru_vdr , & ! vis dir shortwave penetrating to ocean (W/m^2) fswthru_vdf , & ! vis dif shortwave penetrating to ocean (W/m^2) diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 82f5f5ebc..124ce383a 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -23,7 +23,7 @@ module icedrv_step public :: step_therm1, step_therm2, step_dyn_ridge, & prep_radiation, step_radiation, ocean_mixed_layer, & - update_state, biogeochemistry, step_dyn_wave + update_state, biogeochemistry, step_dyn_wave, step_snow !======================================================================= @@ -804,6 +804,82 @@ subroutine step_dyn_ridge (dt, ndtd) end subroutine step_dyn_ridge +!======================================================================= +! +! Updates snow tracers +! +! authors: Elizabeth C. Hunke, LANL +! Nicole Jeffery, LANL + + subroutine step_snow (dt) + + use icedrv_arrays_column, only: rhos_eff, rhos_cmp + use icedrv_domain_size, only: ncat, nslyr, nilyr, nx + use icedrv_flux, only: wind, fresh, fhocn, fsloss, fsnow + use icedrv_state, only: trcrn, vsno, vsnon, vicen, aicen, aice + use icepack_intfc, only: icepack_step_snow + + real (kind=dbl_kind), intent(in) :: & + dt ! time step + + ! local variables + + integer (kind=int_kind) :: & + nt_smice, nt_smliq, nt_rsnw, & + nt_Tsfc, nt_qice, nt_sice, nt_qsno, & + nt_alvl, nt_vlvl, nt_rhos + + integer (kind=int_kind) :: & + i, & ! horizontal index + n ! category index + + real (kind=dbl_kind), dimension(nslyr,ncat) :: & + rhos_effn ! snow effective density: content (kg/m^3) + + character(len=*), parameter :: subname='(step_snow)' + + !----------------------------------------------------------------- + ! query icepack values + !----------------------------------------------------------------- + + call icepack_query_tracer_indices( & + nt_smice_out=nt_smice, nt_smliq_out=nt_smliq, & + nt_rsnw_out=nt_rsnw, nt_Tsfc_out=nt_Tsfc, & + nt_qice_out=nt_qice, nt_sice_out=nt_sice, nt_qsno_out=nt_qsno, & + nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl, nt_rhos_out=nt_rhos) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & + file=__FILE__,line= __LINE__) + + !----------------------------------------------------------------- + ! Snow redistribution and metamorphosis + !----------------------------------------------------------------- + + do i = 1, nx + + rhos_effn(:,:) = c0 + + call icepack_step_snow (dt, nilyr, & + nslyr, ncat, & + wind (i), aice (i), & + aicen(i,:), vicen (i,:), & + vsnon(i,:), trcrn(i,nt_Tsfc,:), & + trcrn(i,nt_qice,:), & ! top layer only + trcrn(i,nt_sice,:), & ! top layer only + trcrn(i,nt_qsno:nt_qsno+nslyr-1,:), & + trcrn(i,nt_alvl,:), trcrn(i,nt_vlvl,:), & + trcrn(i,nt_smice:nt_smice+nslyr-1,:), & + trcrn(i,nt_smliq:nt_smliq+nslyr-1,:), & + trcrn(i,nt_rhos:nt_rhos+nslyr-1,:), & + trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & + rhos_eff (i), rhos_effn(:,:), & + rhos_cmp (i), & + fresh (i), fhocn (i), & + fsloss (i), fsnow (i)) + enddo + + end subroutine step_snow + !======================================================================= ! ! Computes radiation fields From 62202d1626cd9c66adc015f0436f4b140b4b093b Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 19 Feb 2021 15:56:57 -0700 Subject: [PATCH 10/47] call update_state, make optional arguments --- configuration/driver/icedrv_RunMod.F90 | 5 ++++- configuration/driver/icedrv_step.F90 | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/configuration/driver/icedrv_RunMod.F90 b/configuration/driver/icedrv_RunMod.F90 index fda20a6ef..6ed183cd8 100644 --- a/configuration/driver/icedrv_RunMod.F90 +++ b/configuration/driver/icedrv_RunMod.F90 @@ -188,7 +188,10 @@ subroutine ice_step ! snow redistribution and metamorphosis !----------------------------------------------------------------- - if (tr_snow) call step_snow (dt) + if (tr_snow) then + call step_snow (dt) + call update_state (dt) ! clean up + endif ! call icedrv_diagnostics_debug ('post snow redistribution') diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 124ce383a..c6626f75e 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -522,14 +522,16 @@ subroutine update_state (dt, daidt, dvidt, dagedt, offset) use icepack_intfc, only: icepack_aggregate real (kind=dbl_kind), intent(in) :: & - dt , & ! time step - offset ! d(age)/dt time offset = dt for thermo, 0 for dyn + dt ! time step - real (kind=dbl_kind), dimension(:), intent(inout) :: & + real (kind=dbl_kind), dimension(:), intent(inout), optional :: & daidt, & ! change in ice area per time step dvidt, & ! change in ice volume per time step dagedt ! change in ice age per time step + real (kind=dbl_kind), intent(in), optional :: & + offset ! d(age)/dt time offset = dt for thermo, 0 for dyn + integer (kind=int_kind) :: & i, & ! horizontal indices ntrcr, & ! @@ -580,6 +582,8 @@ subroutine update_state (dt, daidt, dvidt, dagedt, offset) nt_strata=nt_strata (1:ntrcr,:)) endif + if (present(offset)) then + !----------------------------------------------------------------- ! Compute thermodynamic area and volume tendencies. !----------------------------------------------------------------- @@ -595,7 +599,8 @@ subroutine update_state (dt, daidt, dvidt, dagedt, offset) dagedt(i) = (trcr(i,nt_iage) & - dagedt(i)) / dt endif - endif + endif ! tr_iage + endif ! present(offset) enddo ! i !$OMP END PARALLEL DO From d2d103807214168864a1a4ca994979fe7135f4f9 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Sun, 21 Feb 2021 16:27:43 -0700 Subject: [PATCH 11/47] snow interactions with thermo (except dEdd) --- columnphysics/icepack_therm_itd.F90 | 23 +- columnphysics/icepack_therm_mushy.F90 | 65 +++- columnphysics/icepack_therm_vertical.F90 | 358 ++++++++++++------ configuration/driver/icedrv_arrays_column.F90 | 7 +- configuration/driver/icedrv_init.F90 | 12 +- configuration/driver/icedrv_step.F90 | 8 +- 6 files changed, 321 insertions(+), 152 deletions(-) diff --git a/columnphysics/icepack_therm_itd.F90 b/columnphysics/icepack_therm_itd.F90 index ba2bc8134..e28704178 100644 --- a/columnphysics/icepack_therm_itd.F90 +++ b/columnphysics/icepack_therm_itd.F90 @@ -24,16 +24,16 @@ module icepack_therm_itd use icepack_parameters, only: p001, p1, p333, p5, p666, puny, bignum use icepack_parameters, only: rhos, rhoi, Lfresh, ice_ref_salinity use icepack_parameters, only: phi_init, dsin0_frazil, hs_ssl, salt_loss - use icepack_parameters, only: rhosi, conserv_check + use icepack_parameters, only: rhosi, conserv_check, rhosmin use icepack_parameters, only: kitd, ktherm, heat_capacity use icepack_parameters, only: z_tracers, solve_zsal, hfrazilmin use icepack_tracers, only: ntrcr, nbtrcr use icepack_tracers, only: nt_qice, nt_qsno, nt_fbri, nt_sice use icepack_tracers, only: nt_apnd, nt_hpnd, nt_aero, nt_isosno, nt_isoice - use icepack_tracers, only: nt_Tsfc, nt_iage, nt_FY, nt_fsd + use icepack_tracers, only: nt_Tsfc, nt_iage, nt_FY, nt_fsd, nt_rhos use icepack_tracers, only: nt_alvl, nt_vlvl - use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow use icepack_tracers, only: tr_iage, tr_FY, tr_lvl, tr_aero, tr_iso, tr_brine, tr_fsd use icepack_tracers, only: n_aero, n_iso use icepack_tracers, only: bio_index @@ -556,6 +556,15 @@ subroutine linear_itd (ncat, hin_max, & trcrn(k,n) = trcrn(k,n) + rhos*Lfresh enddo enddo + ! maintain rhos_cmp positive definiteness + if (tr_snow) then + do n = 1, ncat + do k = nt_rhos, nt_rhos+nslyr-1 + trcrn(k,n) = max(trcrn(k,n)-rhosmin, c0) +! trcrn(k,n) = trcrn(k,n) - rhosmin + enddo + enddo + endif call shift_ice (ntrcr, ncat, & trcr_depend, & @@ -574,6 +583,14 @@ subroutine linear_itd (ncat, hin_max, & trcrn(k,n) = trcrn(k,n) - rhos*Lfresh enddo enddo + ! maintain rhos_cmp positive definiteness + if (tr_snow) then + do n = 1, ncat + do k = nt_rhos, nt_rhos+nslyr-1 + trcrn(k,n) = trcrn(k,n) + rhosmin + enddo + enddo + endif !----------------------------------------------------------------- ! Make sure hice(1) >= minimum ice thickness hi_min. diff --git a/columnphysics/icepack_therm_mushy.F90 b/columnphysics/icepack_therm_mushy.F90 index 1a28ed1c5..9c284455e 100644 --- a/columnphysics/icepack_therm_mushy.F90 +++ b/columnphysics/icepack_therm_mushy.F90 @@ -16,7 +16,7 @@ module icepack_therm_mushy use icepack_mushy_physics, only: temperature_snow, temperature_mush_liquid_fraction use icepack_mushy_physics, only: liquidus_brine_salinity_mush, liquidus_temperature_mush use icepack_mushy_physics, only: conductivity_mush_array, conductivity_snow_array - use icepack_tracers, only: tr_pond + use icepack_tracers, only: tr_pond, tr_snow use icepack_therm_shared, only: surface_heat_flux, dsurface_heat_flux_dTsf use icepack_therm_shared, only: ferrmax use icepack_warnings, only: warnstr, icepack_warnings_add @@ -56,7 +56,8 @@ subroutine temperature_changes_salinity(dt, & fsensn, flatn, & flwoutn, fsurfn, & fcondtop, fcondbot, & - fadvheat, snoice) + fadvheat, snoice, & + smice, smliq) ! solve the enthalpy and bulk salinity of the ice for a single column @@ -89,7 +90,9 @@ subroutine temperature_changes_salinity(dt, & real (kind=dbl_kind), dimension (:), intent(inout) :: & Sswabs , & ! SW radiation absorbed in snow layers (W m-2) - Iswabs ! SW radiation absorbed in ice layers (W m-2) + Iswabs , & ! SW radiation absorbed in ice layers (W m-2) + smice , & ! ice mass tracer in snow (kg/m^3) + smliq ! liquid water mass tracer in snow (kg/m^3) real (kind=dbl_kind), intent(inout):: & fsurfn , & ! net flux to top surface, excluding fcondtopn @@ -348,6 +351,7 @@ subroutine temperature_changes_salinity(dt, & phi, dt, & zSin, Sbr, & sss, qocn, & + smice, smliq, & snoice, fadvheat) if (icepack_warnings_aborted(subname)) return @@ -3204,6 +3208,7 @@ subroutine flood_ice(hsn, hin, & phi, dt, & zSin, Sbr, & sss, qocn, & + smice, smliq, & snoice, fadvheat) ! given upwards flushing brine flow calculate amount of snow ice and @@ -3224,7 +3229,9 @@ subroutine flood_ice(hsn, hin, & zqsn , & ! snow layer enthalpy (J m-2) zqin , & ! ice layer enthalpy (J m-2) zSin , & ! ice layer bulk salinity (ppt) - phi ! ice liquid fraction + phi , & ! ice liquid fraction + smice , & ! ice mass tracer in snow (kg/m^3) + smliq ! liquid water mass tracer in snow (kg/m^3) real(kind=dbl_kind), dimension(:), intent(in) :: & Sbr ! ice layer brine salinity (ppt) @@ -3252,6 +3259,7 @@ subroutine flood_ice(hsn, hin, & zqsn_snowice , & ! snow enthalpy of snow thats becoming snowice (J m-2) freeboard_density , & ! negative of ice surface freeboard times the ocean density (kg m-2) ice_mass , & ! mass of the ice (kg m-2) + snow_mass , & ! mass of the ice (kg m-2) rho_ocn , & ! density of the ocean (kg m-3) ice_density , & ! density of ice layer (kg m-3) hadded , & ! thickness rate of water used from ocean (m/s) @@ -3281,23 +3289,42 @@ subroutine flood_ice(hsn, hin, & enddo ! k ice_mass = ice_mass * hilyr - ! negative freeboard times ocean density - freeboard_density = max(ice_mass + hsn * rhos - hin * rho_ocn, c0) - - ! check if have flooded ice - if (freeboard_density > c0) then - - ! sea ice fraction of newly formed snow ice - phi_snowice = (c1 - rhos / rhoi) - - ! density of newly formed snowice - rho_snowice = phi_snowice * rho_ocn + (c1 - phi_snowice) * rhoi +! for now, do not use variable snow density +! snow_mass = c0 +! if (tr_snow) then +! do k = 1,nslyr +! snow_mass = snow_mass + (smice(k) + smliq(k)) * hslyr +! enddo + +! ! negative freeboard times ocean density +! freeboard_density = max(ice_mass + snow_mass - hin * rho_ocn, c0) ! may not be BFB + +! if (freeboard_density > c0) then ! ice is flooded +! phi_snowice = (c1 - snow_mass / hsn / rhoi) ! sea ice fraction of newly formed snow-ice +! ! density of newly formed snowice +! ! use rhos instead of (c1-phi_snowice)*rhoi to conserve ice and liquid +! ! snow tracers when rhos = smice + smliq +! rho_snowice = phi_snowice * rho_ocn + (c1 - phi_snowice) * rhoi +! endif +! else + ! snow_mass = rhos * hsn + ! negative freeboard times ocean density + freeboard_density = max(ice_mass + hsn * rhos - hin * rho_ocn, c0) + + if (freeboard_density > c0) then ! ice is flooded + phi_snowice = (c1 - rhos / rhoi) ! sea ice fraction of newly formed snow-ice + ! density of newly formed snow-ice + rho_snowice = phi_snowice * rho_ocn + (c1 - phi_snowice) * rhoi + endif ! freeboard_density > c0 +! endif ! tr_snow + + if (freeboard_density > c0) then ! ice is flooded ! calculate thickness of new ice added dh = freeboard_density / (rho_ocn - rho_snowice + rhos) dh = max(min(dh,hsn),c0) - ! enthalpy of snow that becomes snowice + ! enthalpy of snow that becomes snow-ice call enthalpy_snow_snowice(nslyr, dh, hsn, zqsn, zqsn_snowice) if (icepack_warnings_aborted(subname)) return @@ -3316,6 +3343,12 @@ subroutine flood_ice(hsn, hin, & call update_vertical_tracers_snow(nslyr, zqsn, hslyr, hslyr2) if (icepack_warnings_aborted(subname)) return + if (tr_snow .and. hslyr2 > puny) then + call update_vertical_tracers_snow(nslyr, smice, hslyr, hslyr2) + call update_vertical_tracers_snow(nslyr, smliq, hslyr, hslyr2) + if (icepack_warnings_aborted(subname)) return + endif + ! change ice properties call update_vertical_tracers_ice(nilyr, zqin, hilyr, hilyr2, & hin, hin2, zqin_snowice) diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 8fa32f970..f1cd65bc5 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -23,13 +23,13 @@ module icepack_therm_vertical use icepack_parameters, only: c0, c1, p001, p5, puny use icepack_parameters, only: pi, depressT, Lvap, hs_min, cp_ice, min_salin use icepack_parameters, only: cp_ocn, rhow, rhoi, rhos, Lfresh, rhofresh, ice_ref_salinity - use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc + use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc, rsnw_fall, rsnw_tmax use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair use icepack_parameters, only: rfracmin, rfracmax, pndaspect, dpscale, frzpnd use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso - use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow use icepack_tracers, only: n_aero, n_iso use icepack_therm_shared, only: ferrmax, l_brine @@ -83,12 +83,12 @@ subroutine thermo_vertical (nilyr, nslyr, & Tsf, zSin, & zqin, zqsn, & apond, hpond, & - tr_pond_topo,& flw, potT, & Qa, rhoa, & fsnow, fpond, & fbot, Tbot, & - Tsnice, sss, & + Tsnice, sss, & + rsnw, & lhcoef, shcoef, & fswsfc, fswint, & Sswabs, Iswabs, & @@ -98,8 +98,10 @@ subroutine thermo_vertical (nilyr, nslyr, & flwoutn, evapn, & evapsn, evapin, & freshn, fsaltn, & - fhocnn, meltt, & - melts, meltb, & + fhocnn, frain, & + meltt, melts, & + meltb, meltsliq, & + smice, smliq, & congel, snoice, & mlt_onset, frz_onset, & yday, dsnow, & @@ -110,7 +112,8 @@ subroutine thermo_vertical (nilyr, nslyr, & nslyr ! number of snow layers real (kind=dbl_kind), intent(in) :: & - dt ! time step + dt , & ! time step + frain ! rainfall rate (kg/m2/s) ! ice state variables real (kind=dbl_kind), intent(inout) :: & @@ -125,16 +128,16 @@ subroutine thermo_vertical (nilyr, nslyr, & hpond ! melt pond depth (m) ! iage ! ice age (s) - logical (kind=log_kind), intent(in) :: & - tr_pond_topo ! if .true., use melt pond tracer - logical (kind=log_kind), intent(in), optional :: & prescribed_ice ! if .true., use prescribed ice instead of computed real (kind=dbl_kind), dimension (:), intent(inout) :: & zqsn , & ! snow layer enthalpy, zqsn < 0 (J m-3) zqin , & ! ice layer enthalpy, zqin < 0 (J m-3) - zSin ! internal ice layer salinities + zSin , & ! internal ice layer salinities + rsnw , & ! snow grain radius (10^-6 m) + smice , & ! liquid water mass tracer in snow (kg/m^3) + smliq ! ice mass tracer in snow (kg/m^3) ! input from atmosphere real (kind=dbl_kind), & @@ -187,9 +190,10 @@ subroutine thermo_vertical (nilyr, nslyr, & ! diagnostic fields real (kind=dbl_kind), & intent(inout):: & - Tsnice , & ! snow ice interface temperature (deg C) + Tsnice , & ! snow ice interface temperature (deg C) meltt , & ! top ice melt (m/step-->cm/day) melts , & ! snow melt (m/step-->cm/day) + meltsliq , & ! snow melt mass (kg/m^2/step-->kg/m^2/day) meltb , & ! basal ice melt (m/step-->cm/day) congel , & ! basal ice growth (m/step-->cm/day) snoice , & ! snow-ice formation (m/step-->cm/day) @@ -311,8 +315,9 @@ subroutine thermo_vertical (nilyr, nslyr, & sss, & fsensn, flatn, & flwoutn, fsurfn, & - fcondtopn, fcondbotn, & - fadvocn, snoice) + fcondtopn, fcondbotn, & + fadvocn, snoice, & + smice, smliq) if (icepack_warnings_aborted(subname)) return else ! ktherm @@ -399,6 +404,7 @@ subroutine thermo_vertical (nilyr, nslyr, & hin, hilyr, & hsn, hslyr, & zqin, zqsn, & + smice, smliq, & fbot, Tbot, & flatn, fsurfn, & fcondtopn, fcondbotn, & @@ -406,11 +412,12 @@ subroutine thermo_vertical (nilyr, nslyr, & fhocnn, evapn, & evapsn, evapin, & meltt, melts, & + meltsliq, frain, & meltb, & congel, snoice, & mlt_onset, frz_onset, & zSin, sss, & - dsnow) + dsnow, rsnw) if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- @@ -1030,6 +1037,7 @@ subroutine thickness_changes (nilyr, nslyr, & hin, hilyr, & hsn, hslyr, & zqin, zqsn, & + smice, smliq, & fbot, Tbot, & flatn, fsurfn, & fcondtopn, fcondbotn, & @@ -1037,11 +1045,12 @@ subroutine thickness_changes (nilyr, nslyr, & fhocnn, evapn, & evapsn, evapin, & meltt, melts, & + meltsliq, frain, & meltb, & congel, snoice, & mlt_onset, frz_onset,& zSin, sss, & - dsnow) + dsnow, rsnw) integer (kind=int_kind), intent(in) :: & nilyr , & ! number of ice layers @@ -1057,14 +1066,18 @@ subroutine thickness_changes (nilyr, nslyr, & fsnow , & ! snowfall rate (kg m-2 s-1) flatn , & ! surface downward latent heat (W m-2) fsurfn , & ! net flux to top surface, excluding fcondtopn - fcondtopn ! downward cond flux at top surface (W m-2) + fcondtopn , & ! downward cond flux at top surface (W m-2) + frain ! rainfall rate (kg/m2/s) real (kind=dbl_kind), intent(inout) :: & fcondbotn ! downward cond flux at bottom surface (W m-2) real (kind=dbl_kind), dimension (:), intent(inout) :: & zqin , & ! ice layer enthalpy (J m-3) - zqsn ! snow layer enthalpy (J m-3) + zqsn , & ! snow layer enthalpy (J m-3) + rsnw , & ! snow grain radius (10^-6 m) + smice , & ! ice mass tracer in snow (kg/m^3) + smliq ! liquid water mass tracer in snow (kg/m^3) real (kind=dbl_kind), intent(inout) :: & hilyr , & ! ice layer thickness (m) @@ -1073,6 +1086,7 @@ subroutine thickness_changes (nilyr, nslyr, & real (kind=dbl_kind), intent(inout) :: & meltt , & ! top ice melt (m/step-->cm/day) melts , & ! snow melt (m/step-->cm/day) + meltsliq , & ! snow melt mass (kg/m^2/step-->kg/m^2/day) meltb , & ! basal ice melt (m/step-->cm/day) congel , & ! basal ice growth (m/step-->cm/day) snoice , & ! snow-ice formation (m/step-->cm/day) @@ -1131,7 +1145,8 @@ subroutine thickness_changes (nilyr, nslyr, & wk1 , & ! temporary variable zqsnew , & ! enthalpy of new snow (J m-3) hstot , & ! snow thickness including new snow (m) - Tmlts ! melting temperature + Tmlts , & ! melting temperature + smice_fsnow ! ice mass added to snow (kg/m^2) real (kind=dbl_kind), dimension (nilyr+1) :: & zi1 , & ! depth of ice layer boundaries (m) @@ -1145,7 +1160,9 @@ subroutine thickness_changes (nilyr, nslyr, & dzi ! ice layer thickness after growth/melting real (kind=dbl_kind), dimension (nslyr) :: & - dzs ! snow layer thickness after growth/melting + dzs , & ! snow layer thickness after growth/melting + smicetot , & ! total ice mass of snow in each layer (kg/m^2) + smliqtot ! total liquid mass of snow in each layer (kg/m^2) real (kind=dbl_kind), dimension (nilyr) :: & qm , & ! energy of melting (J m-3) = zqin in BL99 formulation @@ -1154,7 +1171,8 @@ subroutine thickness_changes (nilyr, nslyr, & real (kind=dbl_kind) :: & qbotm , & qbotp , & - qbot0 + qbot0 , & + tmp1 ! temporary scalar character(len=*),parameter :: subname='(thickness_changes)' @@ -1172,6 +1190,10 @@ subroutine thickness_changes (nilyr, nslyr, & do k = 1, nslyr dzs(k) = hslyr + smicetot(k) = c0 + smliqtot(k) = c0 + smicetot(k) = dzs(k) * smice(k) + smliqtot(k) = dzs(k) * smliq(k) enddo do k = 1, nilyr @@ -1197,6 +1219,12 @@ subroutine thickness_changes (nilyr, nslyr, & Ts = (Lfresh + zqsn(k)/rhos) / cp_ice if (Ts > c0) then dhs = cp_ice*Ts*dzs(k) / Lfresh + + smice_fsnow = c0 + if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs + smicetot(k) = smicetot(k) - smice_fsnow ! dhs << dzs + smliqtot(k) = smliqtot(k) + smice_fsnow + dzs(k) = dzs(k) - dhs zqsn(k) = -rhos*Lfresh endif @@ -1236,7 +1264,7 @@ subroutine thickness_changes (nilyr, nslyr, & ! is used for changes in the brine energy (emlt_atm). !-------------------------------------------------------------- - evapn = c0 ! initialize + evapn = c0 ! initialize evapsn = c0 ! initialize evapin = c0 ! initialize @@ -1245,6 +1273,7 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(1) = dzs(1) + dhs evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos + smicetot(1) = dhs*rhos + smicetot(1) ! new snow ice else ! add ice with enthalpy zqin(1) dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 dzi(1) = dzi(1) + dhi @@ -1326,6 +1355,12 @@ subroutine thickness_changes (nilyr, nslyr, & dhs = max(-dzs(k), & -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k)) + + smice_fsnow = c0 + if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs + smicetot(k) = smicetot(k) + smice_fsnow ! -dhs <= dzs + smliqtot(k) = smliqtot(k) - smice_fsnow + dzs(k) = dzs(k) + dhs zqsn(k) = -rhos * Lfresh melts = melts - dhs @@ -1339,6 +1374,11 @@ subroutine thickness_changes (nilyr, nslyr, & qsub = zqsn(k) - rhos*Lvap ! qsub < 0 dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 + + smice_fsnow = c0 + if (abs(dzs(k)) > puny) smice_fsnow = dhs * smicetot(k)/dzs(k) + smicetot(k) = smicetot(k) + smice_fsnow + dzs(k) = dzs(k) + dhs esub = esub - dhs*qsub esub = max(esub, c0) ! in case of roundoff error @@ -1350,6 +1390,12 @@ subroutine thickness_changes (nilyr, nslyr, & !-------------------------------------------------------------- dhs = max(-dzs(k), etop_mlt/zqsn(k)) + + smice_fsnow = c0 + if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs + smicetot(k) = smicetot(k) + smice_fsnow + smliqtot(k) = smliqtot(k) - smice_fsnow + dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 etop_mlt = etop_mlt - dhs*zqsn(k) etop_mlt = max(etop_mlt, c0) ! in case of roundoff error @@ -1461,15 +1507,24 @@ subroutine thickness_changes (nilyr, nslyr, & hstot = dzs(1) + hsn_new if (hstot > c0) then - zqsn(1) = (dzs(1) * zqsn(1) & + zqsn(1) = (dzs(1) * zqsn(1) & + hsn_new * zqsnew) / hstot - ! avoid roundoff errors - zqsn(1) = min(zqsn(1), -rhos*Lfresh) + zqsn(1) = min(zqsn(1), -rhos*Lfresh) ! avoid roundoff errors + + ! ice mass in snow due to snowfall + ! new snow density = rhos for now !echmod - fix this + smicetot(1) = smicetot(1) + hsn_new * rhos ! kg/m^2 dzs(1) = hstot endif endif +!---!----------------------------------------------------------------- +!---! Add rain at top surface (only to liquid tracer) +!---!----------------------------------------------------------------- + + smliqtot(1) = smliqtot(1) + frain*dt + !----------------------------------------------------------------- ! Find the new ice and snow thicknesses. !----------------------------------------------------------------- @@ -1486,6 +1541,17 @@ subroutine thickness_changes (nilyr, nslyr, & dsnow = dsnow + dzs(k) - hslyr enddo ! k + !------------------------------------------------------------------- + ! Incorporate new snow for snow grain radius + !------------------------------------------------------------------- + + if (tr_snow .and. hsn_new > c0) then + tmp1 = max(c0, dzs(1) - hsn_new) + rsnw(1) = (rsnw_fall * hsn_new + rsnw(1) * tmp1) & + / max( hsn_new + tmp1, puny) + rsnw(1) = max(rsnw_fall, min(rsnw_tmax, rsnw(1))) + endif + !------------------------------------------------------------------- ! Convert snow to ice if snow lies below freeboard. !------------------------------------------------------------------- @@ -1496,9 +1562,27 @@ subroutine thickness_changes (nilyr, nslyr, & hin, hsn, & zqin, zqsn, & dzi, dzs, & - dsnow) + dsnow, & + smicetot(:), & + smliqtot(:)) if (icepack_warnings_aborted(subname)) return + !------------------------------------------------------------------- + ! Update snow mass tracers, smice and smliq, for uneven layers + !------------------------------------------------------------------- + if (tr_snow) then + do k = 1, nslyr + meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) + if (dzs(k) > c0) then + smice(k) = smicetot(k) / dzs(k) + smliq(k) = smliqtot(k) / dzs(k) + else + smice(k) = c0 + smliq(k) = c0 + endif + enddo + endif + !---!------------------------------------------------------------------- !---! Repartition the ice and snow into equal-thickness layers, !---! conserving energy. @@ -1583,13 +1667,28 @@ subroutine thickness_changes (nilyr, nslyr, & !----------------------------------------------------------------- ! Conserving energy, compute the enthalpy of the new equal layers. + ! Also adjust snow grain radius, ice content and liquid content. !----------------------------------------------------------------- call adjust_enthalpy (nslyr, & zs1, zs2, & hslyr, hsn, & zqsn) - if (icepack_warnings_aborted(subname)) return + if (tr_snow) then + call adjust_enthalpy (nslyr, & + zs1(:), zs2(:), & + hslyr, hsn, & + rsnw(:)) + call adjust_enthalpy (nslyr, & + zs1(:), zs2(:), & + hslyr, hsn, & + smice(:)) + call adjust_enthalpy (nslyr, & + zs1(:), zs2(:), & + hslyr, hsn, & + smliq(:)) + endif + if (icepack_warnings_aborted(subname)) return endif ! nslyr > 1 @@ -1603,6 +1702,11 @@ subroutine thickness_changes (nilyr, nslyr, & fhocnn = fhocnn & + zqsn(k)*hsn/(real(nslyr,kind=dbl_kind)*dt) zqsn(k) = -rhos*Lfresh + + meltsliq = meltsliq + smicetot(k) ! add to meltponds + smice(k) = c0 + smliq(k) = c0 + hslyr = c0 endif enddo @@ -1651,7 +1755,8 @@ subroutine freeboard (nslyr, & hin, hsn, & zqin, zqsn, & dzi, dzs, & - dsnow) + dsnow, smicetot, & + smliqtot) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -1676,7 +1781,9 @@ subroutine freeboard (nslyr, & real (kind=dbl_kind), dimension (:), intent(inout) :: & zqin , & ! ice layer enthalpy (J m-3) dzi , & ! ice layer thicknesses (m) - dzs ! snow layer thicknesses (m) + dzs , & ! snow layer thicknesses (m) + smicetot, & ! snow ice mass per layer (kg/m^2) + smliqtot ! snow liquid mass per layer (kg/m^2) ! local variables @@ -1702,7 +1809,7 @@ subroutine freeboard (nslyr, & dhsn = c0 hqs = c0 - wk1 = hsn - hin*(rhow-rhoi)/rhos + wk1 = hsn - hin*(rhow-rhoi)/rhos ! not yet consistent with smice/smliq !echmod - fix this if (wk1 > puny .and. hsn > puny) then ! snow below freeboard dhsn = min(wk1*rhoi/rhow, hsn) ! snow to remove @@ -1718,7 +1825,11 @@ subroutine freeboard (nslyr, & if (dhin > puny) then dhs = min(dhsn, dzs(k)) ! snow to remove from layer hsn = hsn - dhs - dsnow = dsnow -dhs !new snow addition term + dsnow = dsnow - dhs ! new snow + + smicetot(k) = smicetot(k) - dhs * smicetot(k) / dzs(k) + smliqtot(k) = smliqtot(k) - dhs * smliqtot(k) / dzs(k) + dzs(k) = dzs(k) - dhs dhsn = dhsn - dhs dhsn = max(dhsn,c0) @@ -2028,7 +2139,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & congel , congeln , & snoice , snoicen , & dsnow , dsnown , & - meltsliqn , & + meltsliqn , rsnwn , & smicen , smliqn , & lmask_n , lmask_s , & mlt_onset , frz_onset , & @@ -2142,6 +2253,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & meltsliqn ! mass of snow melt (kg/m^2) real (kind=dbl_kind), dimension(:,:), optional, intent(inout) :: & + rsnwn , & ! snow grain radius (10^-6 m) smicen , & ! mass of ice in snow (kg/m^2) smliqn ! mass of liquid in snow (kg/m^2) @@ -2256,6 +2368,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_meltsliq ! mass of snow melt (kg/m^2) real (kind=dbl_kind), allocatable, dimension(:,:) :: & + l_rsnw , & ! snow grain radius (10^-6 m) l_smice , & ! mass of ice in snow (kg/m^2) l_smliq ! mass of liquid in snow (kg/m^2) @@ -2350,59 +2463,49 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_H2_18O_ocn = c0 if (present(H2_18O_ocn)) l_H2_18O_ocn = H2_18O_ocn - l_fswthru_vdr = c0 - if (present(fswthru_vdr) ) l_fswthru_vdr = fswthru_vdr + l_fswthru_vdr = c0 + if (present(fswthru_vdr)) l_fswthru_vdr = fswthru_vdr - l_fswthru_vdf = c0 - if (present(fswthru_vdf) ) l_fswthru_vdf = fswthru_vdf + l_fswthru_vdf = c0 + if (present(fswthru_vdf)) l_fswthru_vdf = fswthru_vdf - l_fswthru_idr = c0 - if (present(fswthru_idr) ) l_fswthru_idr = fswthru_idr + l_fswthru_idr = c0 + if (present(fswthru_idr)) l_fswthru_idr = fswthru_idr - l_fswthru_idf = c0 - if (present(fswthru_idf) ) l_fswthru_idf = fswthru_idf + l_fswthru_idf = c0 + if (present(fswthru_idf)) l_fswthru_idf = fswthru_idf allocate(l_fswthrun_vdr(ncat)) - allocate(l_fswthrun_vdf(ncat)) - allocate(l_fswthrun_idr(ncat)) - allocate(l_fswthrun_idf(ncat)) + l_fswthrun_vdr = c0 + if (present(fswthrun_vdr)) l_fswthrun_vdr = fswthrun_vdr - l_fswthrun_vdr = c0 - if (present(fswthrun_vdr) ) l_fswthrun_vdr = fswthrun_vdr + allocate(l_fswthrun_vdf(ncat)) + l_fswthrun_vdf = c0 + if (present(fswthrun_vdf)) l_fswthrun_vdf = fswthrun_vdf - l_fswthrun_vdf = c0 - if (present(fswthrun_vdf) ) l_fswthrun_vdf = fswthrun_vdf + allocate(l_fswthrun_idr(ncat)) + l_fswthrun_idr = c0 + if (present(fswthrun_idr)) l_fswthrun_idr = fswthrun_idr - l_fswthrun_idr = c0 - if (present(fswthrun_idr) ) l_fswthrun_idr = fswthrun_idr + allocate(l_fswthrun_idf(ncat)) + l_fswthrun_idf = c0 + if (present(fswthrun_idf)) l_fswthrun_idf = fswthrun_idf - l_fswthrun_idf = c0 - if (present(fswthrun_idf) ) l_fswthrun_idf = fswthrun_idf + allocate(l_meltsliq(ncat)) + l_meltsliq = c0 + if (present(meltsliqn)) l_meltsliq = meltsliqn -!echmod: make a subroutine to do this for each array? - if (present(meltsliqn) ) then - allocate(l_meltsliq(size(meltsliqn))) - l_meltsliq = meltsliqn - else - allocate(l_meltsliq(1)) - l_meltsliq = c0 - endif + allocate(l_rsnw(nslyr,ncat)) + l_rsnw = c0 ! echmod: this should be the default radius + if (present(rsnwn)) l_rsnw = rsnwn - if (present(smicen) ) then - allocate(l_smice(size(smicen,dim=1),size(smicen,dim=2))) - l_smice = smicen - else - allocate(l_smice(1,1)) - l_smice = c0 - endif + allocate(l_smice(nslyr,ncat)) + l_smice = c0 + if (present(smicen)) l_smice = smicen - if (present(smliqn) ) then - allocate(l_smliq(size(smliqn,dim=1),size(smliqn,dim=2))) - l_smliq = smliqn - else - allocate(l_smliq(1,1)) - l_smliq = c0 - endif + allocate(l_smliq(nslyr,ncat)) + l_smliq = c0 + if (present(smliqn)) l_smliq = smliqn !----------------------------------------------------------------- ! Adjust frzmlt to account for ice-ocean heat fluxes since last @@ -2549,36 +2652,37 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & if (icepack_warnings_aborted(subname)) return endif - call thermo_vertical(nilyr, nslyr, & - dt, aicen (n), & - vicen (n), vsnon (n), & - Tsfc (n), zSin (:,n), & - zqin (:,n), zqsn (:,n), & - apnd (n), hpnd (n), & - tr_pond_topo, & - flw, potT, & - Qa, rhoa, & - fsnow, fpond, & - fbot, Tbot, & - Tsnice, sss, & - lhcoef, shcoef, & - fswsfcn (n), fswintn (n), & - Sswabsn(:,n), Iswabsn(:,n), & - fsurfn (n), fcondtopn(n), & - fcondbotn(n), & - fsensn (n), flatn (n), & - flwoutn, evapn, & - evapsn, evapin, & - freshn, fsaltn, & - fhocnn, & - melttn (n), meltsn (n), & - meltbn (n), & - congeln (n), snoicen (n), & - mlt_onset, frz_onset, & - yday, dsnown (n), & - prescribed_ice) - - if (icepack_warnings_aborted(subname)) then + call thermo_vertical(nilyr=nilyr, nslyr=nslyr, & + dt=dt, aicen=aicen (n), & + vicen=vicen (n), vsnon=vsnon (n), & + Tsf=Tsfc (n), zSin=zSin (:,n), & + zqin=zqin (:,n), zqsn=zqsn (:,n), & + apond=apnd (n), hpond=hpnd (n), & + flw=flw, potT=potT, & + Qa=Qa, rhoa=rhoa, & + fsnow=fsnow, fpond=fpond, & + fbot=fbot, Tbot=Tbot, & + Tsnice=Tsnice, sss=sss, & + rsnw=l_rsnw (:,n), & + lhcoef=lhcoef, shcoef=shcoef, & + fswsfc=fswsfcn (n), fswint=fswintn (n), & + Sswabs=Sswabsn(:,n), Iswabs=Iswabsn(:,n), & + fsurfn=fsurfn (n), fcondtopn=fcondtopn(n), & + fcondbotn=fcondbotn(n), & + fsensn=fsensn (n), flatn=flatn (n), & + flwoutn=flwoutn, evapn=evapn, & + evapsn=evapsn, evapin=evapin, & + freshn=freshn, fsaltn=fsaltn, & + fhocnn=fhocnn, frain=frain, & + meltt=melttn (n), melts=meltsn (n), & + meltb=meltbn (n), meltsliq=l_meltsliq(n), & + smice=l_smice (:,n), smliq=l_smliq (:,n), & + congel=congeln (n), snoice=snoicen (n), & + mlt_onset=mlt_onset, frz_onset=frz_onset, & + yday=yday, dsnow=dsnown (n), & + prescribed_ice=prescribed_ice) + + if (icepack_warnings_aborted(subname)) then call icepack_warnings_add(subname//' ice: Vertical thermo error: ') return endif @@ -2630,11 +2734,11 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & endif endif ! aicen_init - if (use_smliq_pnd) then !echmod make sure tr_snow=T too - call drain_snow (dt = dt, nslyr = nslyr, & - vsnon = vsnon(n), aicen = aicen(n), & - smice = smicen(:,n), smliq = smliqn(:,n), & - meltsliq = meltsliqn(n)) + if (tr_snow .and. use_smliq_pnd) then + call drain_snow (dt = dt, nslyr = nslyr, & + vsnon = vsnon(n), aicen = aicen(n), & + smice = l_smice(:,n), smliq = l_smliq(:,n), & + meltsliq = l_meltsliq(n)) endif !----------------------------------------------------------------- @@ -2759,21 +2863,25 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & enddo ! ncat - if (present(isosno) ) isosno = l_isosno - if (present(isoice) ) isoice = l_isoice - if (present(Qa_iso) ) Qa_iso = l_Qa_iso - if (present(Qref_iso) ) Qref_iso = l_Qref_iso - if (present(fiso_atm) ) fiso_atm = l_fiso_atm - if (present(fiso_ocn) ) fiso_ocn = l_fiso_ocn - if (present(fiso_evap)) fiso_evap= l_fiso_evap - if (present(fswthrun_vdr)) fswthrun_vdr= l_fswthrun_vdr - if (present(fswthrun_vdf)) fswthrun_vdf= l_fswthrun_vdf - if (present(fswthrun_idr)) fswthrun_idr= l_fswthrun_idr - if (present(fswthrun_idf)) fswthrun_idf= l_fswthrun_idf - if (present(fswthru_vdr)) fswthru_vdr= l_fswthru_vdr - if (present(fswthru_vdf)) fswthru_vdf= l_fswthru_vdf - if (present(fswthru_idr)) fswthru_idr= l_fswthru_idr - if (present(fswthru_idf)) fswthru_idf= l_fswthru_idf + if (present(isosno )) isosno = l_isosno + if (present(isoice )) isoice = l_isoice + if (present(Qa_iso )) Qa_iso = l_Qa_iso + if (present(Qref_iso )) Qref_iso = l_Qref_iso + if (present(fiso_atm )) fiso_atm = l_fiso_atm + if (present(fiso_ocn )) fiso_ocn = l_fiso_ocn + if (present(fiso_evap )) fiso_evap = l_fiso_evap + if (present(fswthrun_vdr)) fswthrun_vdr = l_fswthrun_vdr + if (present(fswthrun_vdf)) fswthrun_vdf = l_fswthrun_vdf + if (present(fswthrun_idr)) fswthrun_idr = l_fswthrun_idr + if (present(fswthrun_idf)) fswthrun_idf = l_fswthrun_idf + if (present(fswthru_vdr )) fswthru_vdr = l_fswthru_vdr + if (present(fswthru_vdf )) fswthru_vdf = l_fswthru_vdf + if (present(fswthru_idr )) fswthru_idr = l_fswthru_idr + if (present(fswthru_idf )) fswthru_idf = l_fswthru_idf + if (present(meltsliqn )) meltsliqn = l_meltsliq + if (present(rsnwn )) rsnwn = l_rsnw + if (present(smicen )) smicen = l_smice + if (present(smliqn )) smliqn = l_smliq deallocate(l_isosno) deallocate(l_isoice) deallocate(l_Qa_iso) @@ -2785,6 +2893,10 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & deallocate(l_fswthrun_vdf) deallocate(l_fswthrun_idr) deallocate(l_fswthrun_idf) + deallocate(l_meltsliq) + deallocate(l_rsnw) + deallocate(l_smice) + deallocate(l_smliq) !----------------------------------------------------------------- ! Calculate ponds from the topographic scheme diff --git a/configuration/driver/icedrv_arrays_column.F90 b/configuration/driver/icedrv_arrays_column.F90 index db52df2a0..d8452153c 100644 --- a/configuration/driver/icedrv_arrays_column.F90 +++ b/configuration/driver/icedrv_arrays_column.F90 @@ -66,7 +66,12 @@ module icedrv_arrays_column real (kind=dbl_kind), public, & dimension (nx) :: & rhos_eff , & ! mean effective snow density: content (kg/m^3) - rhos_cmp ! mean effective snow density: compaction (kg/m^3) + rhos_cmp , & ! mean effective snow density: compaction (kg/m^3) + meltsliq ! snow melt mass (kg/m^2/step-->kg/m^2/day) + + real (kind=dbl_kind), & + dimension (nx,ncat), public, save :: & + meltsliqn ! snow melt mass in category n (kg/m^2) ! icepack_meltpond_lvl.F90 real (kind=dbl_kind), public, & diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index d44b99b22..150460737 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -424,24 +424,20 @@ subroutine input_data if (snwredist(1:4) /= 'none' .and. .not. tr_snow) then write (nu_diag,*) 'WARNING: snwredist on but tr_snow=F' - write (nu_diag,*) 'WARNING: Setting snwredist=none' - snwredist = 'none' + call icedrv_system_abort(file=__FILE__,line=__LINE__) endif if (snwredist(1:9) == '30percent' .and. .not. tr_lvl) then write (nu_diag,*) 'WARNING: snwredist=30percent but tr_lvl=F' - write (nu_diag,*) 'WARNING: Setting tr_lvl=T' - tr_lvl = .true. + call icedrv_system_abort(file=__FILE__,line=__LINE__) endif if (snwredist(1:6) == 'ITDrdg' .and. .not. tr_lvl) then write (nu_diag,*) 'WARNING: snwredist=ITDrdg but tr_lvl=F' - write (nu_diag,*) 'WARNING: Setting tr_lvl=T' - tr_lvl = .true. + call icedrv_system_abort(file=__FILE__,line=__LINE__) endif if (use_smliq_pnd .and. .not. tr_snow) then write (nu_diag,*) 'WARNING: use_smliq_pnd = T but' write (nu_diag,*) 'WARNING: snow tracers are not active' - write (nu_diag,*) 'WARNING: Setting use_smliq_pnd = F' - use_smliq_pnd = .false. + call icedrv_system_abort(file=__FILE__,line=__LINE__) endif if (tr_iso .and. n_iso==0) then diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index c6626f75e..fca656ec9 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -108,6 +108,7 @@ subroutine step_therm1 (dt) use icedrv_arrays_column, only: hkeel, dkeel, lfloe, dfloe use icedrv_arrays_column, only: fswsfcn, fswintn, Sswabsn, Iswabsn use icedrv_arrays_column, only: fswthrun, fswthrun_vdr, fswthrun_vdf, fswthrun_idr, fswthrun_idf + use icedrv_arrays_column, only: meltsliqn, meltsliq use icedrv_calendar, only: yday use icedrv_domain_size, only: ncat, nilyr, nslyr, n_aero, n_iso, nx use icedrv_flux, only: frzmlt, sst, Tf, strocnxT, strocnyT, rside, fside, & @@ -149,7 +150,7 @@ subroutine step_therm1 (dt) integer (kind=int_kind) :: & ntrcr, nt_apnd, nt_hpnd, nt_ipnd, nt_alvl, nt_vlvl, nt_Tsfc, & nt_iage, nt_FY, nt_qice, nt_sice, nt_qsno, & - nt_aero, nt_isosno, nt_isoice + nt_aero, nt_isosno, nt_isoice, nt_rsnw, nt_smice, nt_smliq logical (kind=log_kind) :: & tr_iage, tr_FY, tr_aero, tr_iso, tr_pond, tr_pond_cesm, & @@ -197,6 +198,7 @@ subroutine step_therm1 (dt) nt_iage_out=nt_iage, nt_FY_out=nt_FY, & nt_qice_out=nt_qice, nt_sice_out=nt_sice, & nt_aero_out=nt_aero, nt_qsno_out=nt_qsno, & + nt_rsnw_out=nt_rsnw, nt_smice_out=nt_smice, nt_smliq_out=nt_smliq, & nt_isosno_out=nt_isosno, nt_isoice_out=nt_isoice) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -272,6 +274,9 @@ subroutine step_therm1 (dt) ipnd = trcrn(i,nt_ipnd,:), & iage = trcrn(i,nt_iage,:), & FY = trcrn(i,nt_FY,:), & + rsnwn = trcrn(i,nt_rsnw :nt_rsnw +nslyr-1,:), & + smicen = trcrn(i,nt_smice:nt_smice+nslyr-1,:), & + smliqn = trcrn(i,nt_smliq:nt_smliq+nslyr-1,:), & aerosno = aerosno(:,:,:), & aeroice = aeroice(:,:,:), & isosno = isosno(:,:), & @@ -347,6 +352,7 @@ subroutine step_therm1 (dt) congel = congel(i), congeln = congeln(i,:), & snoice = snoice(i), snoicen = snoicen(i,:), & dsnow = dsnow(i), dsnown = dsnown(i,:), & + meltsliqn=meltsliqn(i,:), & lmask_n = lmask_n(i), lmask_s = lmask_s(i), & mlt_onset=mlt_onset(i), frz_onset = frz_onset(i), & yday = yday, prescribed_ice = prescribed_ice) From 8fc99aeaac15a76e0af40e4ec36e901032a23dac Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Sun, 21 Feb 2021 18:56:57 -0700 Subject: [PATCH 12/47] snow interactions in dEdd --- columnphysics/icepack_shortwave.F90 | 133 ++++++++++++++++++++++----- configuration/driver/icedrv_init.F90 | 5 + 2 files changed, 113 insertions(+), 25 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 2240f40a9..2d88ffadb 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -44,13 +44,13 @@ module icepack_shortwave use icepack_parameters, only: c0, c1, c1p5, c2, c3, c4, c10 use icepack_parameters, only: p01, p1, p15, p25, p5, p75, puny use icepack_parameters, only: albocn, Timelt, snowpatch, awtvdr, awtidr, awtvdf, awtidf - use icepack_parameters, only: kappav, hs_min, rhofresh, rhos, nspint - use icepack_parameters, only: hi_ssl, hs_ssl, min_bgc, sk_l + use icepack_parameters, only: kappav, hs_min, rhofresh, rhos, nspint, rsnw_fall, snwredist + use icepack_parameters, only: hi_ssl, hs_ssl, min_bgc, sk_l, snwlvlfac use icepack_parameters, only: z_tracers, skl_bgc, calc_tsfc, shortwave, kalg, heat_capacity use icepack_parameters, only: r_ice, r_pnd, r_snw, dt_mlt, rsnw_mlt, hs0, hs1, hp1 use icepack_parameters, only: pndaspect, albedo_type, albicev, albicei, albsnowv, albsnowi, ahmax use icepack_tracers, only: ntrcr, nbtrcr_sw - use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow use icepack_tracers, only: tr_bgc_N, tr_aero use icepack_tracers, only: nt_bgc_N, nt_zaero, tr_bgc_N use icepack_tracers, only: tr_zaero, nlt_chl_sw, nlt_zaero_sw @@ -804,6 +804,8 @@ subroutine run_dEdd(dt, ncat, & albpndn, apeffn, & snowfracn, & dhsn, ffracn, & + rsnow, & + rsnw_dEddn, & l_print_point, & initonly) @@ -875,10 +877,12 @@ subroutine run_dEdd(dt, ncat, & ipndn ! pond refrozen lid thickness (m) real(kind=dbl_kind), dimension(:,:), intent(in) :: & + rsnow, & ! snow grain radius tracer (10^-6 m) aeron, & ! aerosols (kg/m^3) trcrn_bgcsw ! zaerosols (kg/m^3) + chlorophyll on shorthwave grid real(kind=dbl_kind), dimension(:), intent(inout) :: & + rsnw_dEddn, & ! snow grain radius if .not. tr_rsnw (10^-6 m) ffracn,& ! fraction of fsurfn used to melt ipond dhsn ! depth difference for snow on sea ice and pond ice @@ -922,7 +926,10 @@ subroutine run_dEdd(dt, ncat, & ! snow variables for Delta-Eddington shortwave real (kind=dbl_kind) :: & fsn , & ! snow horizontal fraction - hsn ! snow depth (m) + hsn , & ! snow depth (m) + hsnlvl , & ! snow depth over level ice (m) + vsn , & ! snow volume + alvl ! area fraction of level ice real (kind=dbl_kind), dimension (nslyr) :: & rhosnwn , & ! snow density (kg/m3) @@ -934,7 +941,8 @@ subroutine run_dEdd(dt, ncat, & hpn ! actual pond depth (m) integer (kind=int_kind) :: & - n ! thickness category index + n , & ! thickness category index + k ! snow layer index real (kind=dbl_kind) :: & ipn , & ! refrozen pond ice thickness (m), mean over ice fraction @@ -945,6 +953,7 @@ subroutine run_dEdd(dt, ncat, & hmx , & ! maximum available snow infiltration equivalent depth dhs , & ! local difference in snow depth on sea ice and pond ice spn , & ! snow depth on refrozen pond (m) + rnslyr , & ! 1/nslyr tmp ! 0 or 1 logical (kind=log_kind) :: & @@ -989,8 +998,9 @@ subroutine run_dEdd(dt, ncat, & hsn = c0 rhosnwn(:) = c0 rsnwn(:) = c0 - apeffn(n) = c0 ! for history - snowfracn(n) = c0 ! for history + apeffn(n) = c0 ! for history + snowfracn(n) = c0 ! for history + rsnw_dEddn(n) = c0 ! for history if (aicen(n) > puny) then @@ -999,7 +1009,8 @@ subroutine run_dEdd(dt, ncat, & aicen(n), vsnon(n), & Tsfcn(n), fsn, & hs0, hsn, & - rhosnwn, rsnwn) + rhosnwn, rsnwn, & + rsnow(:,n)) if (icepack_warnings_aborted(subname)) return ! set pond properties @@ -1019,6 +1030,28 @@ subroutine run_dEdd(dt, ncat, & fsn = min(fsn, c1-fpn) apeffn(n) = fpn ! for history elseif (tr_pond_lvl) then + + hsnlvl = hsn ! initialize + if (trim(snwredist) == '30percentsw') then + hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) + ! snow volume over level ice + alvl = aicen(n) * alvln(n) + if (alvl > puny) then + vsn = hsnlvl * alvl + else + vsn = vsnon(n) + alvl = aicen(n) + endif + ! set snow properties over level ice + call shortwave_dEdd_set_snow(nslyr, R_snw, & + dT_mlt, rsnw_mlt, & + alvl, vsn, & + Tsfcn(n), fsn, & + hs0, hsnlvl, & + rhosnwn(:), rsnwn(:), & + rsnow(:,n)) + endif ! snwredist + fpn = c0 ! fraction of ice covered in pond hpn = c0 ! pond depth over fpn ! refrozen pond lid thickness avg over ice @@ -1027,8 +1060,8 @@ subroutine run_dEdd(dt, ncat, & dhs = dhsn(n) ! snow depth difference, sea ice - pond if (.not. linitonly .and. ipn > puny .and. & dhs < puny .and. fsnow*dt > hs_min) & - dhs = hsn - fsnow*dt ! initialize dhs>0 - spn = hsn - dhs ! snow depth on pond ice + dhs = hsnlvl - fsnow*dt ! initialize dhs>0 + spn = hsnlvl - dhs ! snow depth on pond ice if (.not. linitonly .and. ipn*spn < puny) dhs = c0 dhsn(n) = dhs ! save: constant until reset to 0 @@ -1053,7 +1086,7 @@ subroutine run_dEdd(dt, ncat, & ! infiltrate snow hp = hpn if (hp > puny) then - hs = hsn + hs = hsnlvl rp = rhofresh*hp/(rhofresh*hp + rhos*hs) if (rp < p15) then fpn = c0 @@ -1063,7 +1096,7 @@ subroutine run_dEdd(dt, ncat, & tmp = max(c0, sign(c1, hp-hmx)) ! 1 if hp>=hmx, else 0 hp = (rhofresh*hp + rhos*hs*tmp) & / (rhofresh - rhos*(c1-tmp)) - hsn = hs - hp*fpn*(c1-tmp) + hsn = hsn - hp*fpn*(c1-tmp) hpn = hp * tmp fpn = fpn * tmp endif @@ -1135,10 +1168,10 @@ subroutine run_dEdd(dt, ncat, & alidrn(n), alidfn(n), & fswsfcn(n), fswintn(n), & fswthru=fswthrun(n), & - fswthru_vdr=l_fswthrun_vdr(n), & - fswthru_vdf=l_fswthrun_vdf(n), & - fswthru_idr=l_fswthrun_idr(n), & - fswthru_idf=l_fswthrun_idf(n), & + fswthru_vdr=l_fswthrun_vdr(n), & + fswthru_vdf=l_fswthrun_vdf(n), & + fswthru_idr=l_fswthrun_idr(n), & + fswthru_idf=l_fswthrun_idf(n), & Sswabs=Sswabsn(:,n), & Iswabs=Iswabsn(:,n), & albice=albicen(n), & @@ -1150,6 +1183,13 @@ subroutine run_dEdd(dt, ncat, & if (icepack_warnings_aborted(subname)) return + if (.not. tr_snow) then + rnslyr = c1/max(c1,(real(nslyr,kind=dbl_kind))) + do k = 1,nslyr + rsnw_dEddn(n) = rsnw_dEddn(n) + rsnwn(k)*rnslyr + enddo + endif + endif ! aicen > puny enddo ! ncat @@ -3569,7 +3609,8 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & aice, vsno, & Tsfc, fs, & hs0, hs, & - rhosnw, rsnw) + rhosnw, rsnw, & + rsnow) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -3589,6 +3630,9 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & fs , & ! horizontal coverage of snow hs ! snow depth + real (kind=dbl_kind), dimension (:), intent(in) :: & + rsnow ! snow grain radius tracer (micro-meters) + real (kind=dbl_kind), dimension (:), intent(out) :: & rhosnw , & ! density in snow layer (kg/m3) rsnw ! grain radius in snow layer (micro-meters) @@ -3621,6 +3665,15 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & if (hs0 > puny) fs = min(hs/hs0, c1) endif + if (tr_snow) then ! use snow grain tracer + + do ks = 1, nslyr + rsnw(ks) = max(rsnw_fall,rsnow(ks)) + rhosnw(ks) = rhos + enddo + + else + ! bare ice, temperature dependence dTs = Timelt - Tsfc fT = -min(dTs/dT_mlt-c1,c0) @@ -3637,7 +3690,9 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT rsnw(ks) = max(rsnw(ks), rsnw_fresh) rsnw(ks) = min(rsnw(ks), rsnw_mlt) - enddo ! ks + enddo ! ks + + endif ! tr_snow end subroutine shortwave_dEdd_set_snow @@ -4010,6 +4065,7 @@ subroutine icepack_step_radiation (dt, ncat, & albpndn, apeffn, & snowfracn, & dhsn, ffracn, & + rsnow, rsnw_dEddn,& l_print_point, & initonly) @@ -4113,6 +4169,12 @@ subroutine icepack_step_radiation (dt, ncat, & dEdd_algae , & ! .true. use prognostic chla in dEdd modal_aero ! .true. use modal aerosol optical treatment + real (kind=dbl_kind), dimension(:,:), intent(in), optional :: & + rsnow ! snow grain radius tracer (10^-6 m) + + real(kind=dbl_kind), dimension(:), intent(inout), optional :: & + rsnw_dEddn ! snow grain radius if .not. tr_snow (10^-6 m) + logical (kind=log_kind), optional :: & initonly ! flag to indicate init only, default is false @@ -4134,7 +4196,11 @@ subroutine icepack_step_radiation (dt, ncat, & l_fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) l_fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) l_fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - l_fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + l_fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) + l_rsnw_dEddn ! snow grain radius if .not. tr_snow (10^-6 m) + + real (kind=dbl_kind), dimension(:,:), allocatable :: & + l_rsnow ! snow grain radius tracer (10^-6 m) character(len=*),parameter :: subname='(icepack_step_radiation)' @@ -4143,12 +4209,20 @@ subroutine icepack_step_radiation (dt, ncat, & allocate(l_fswthrun_idr(ncat)) allocate(l_fswthrun_idf(ncat)) - hin = c0 - hbri = c0 - linitonly = .false. - if (present(initonly)) then - linitonly = initonly - endif + hin = c0 + hbri = c0 + linitonly = .false. + if (present(initonly)) then + linitonly = initonly + endif + + allocate(l_rsnow (nslyr,ncat)) + l_rsnow = c0 + if (present(rsnow)) l_rsnow = rsnow + + allocate(l_rsnw_dEddn (ncat)) + l_rsnw_dEddn = c0 + if (present(rsnw_dEddn)) l_rsnw_dEddn = rsnw_dEddn ! Initialize do n = 1, ncat @@ -4234,6 +4308,8 @@ subroutine icepack_step_radiation (dt, ncat, & snowfracn=snowfracn, & dhsn=dhsn, & ffracn=ffracn, & + rsnow=l_rsnow, & + rsnw_dEddn=l_rsnw_dEddn, & l_print_point=l_print_point, & initonly=linitonly) if (icepack_warnings_aborted(subname)) return @@ -4321,8 +4397,15 @@ subroutine icepack_step_radiation (dt, ncat, & deallocate(l_fswthrun_idr) deallocate(l_fswthrun_idf) + if (present(rsnw_dEddn)) rsnw_dEddn = l_rsnw_dEddn + + deallocate(l_rsnow) + deallocate(l_rsnw_dEddn) + end subroutine icepack_step_radiation +!======================================================================= + ! Delta-Eddington solution expressions !======================================================================= diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 150460737..df72341b6 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -461,6 +461,11 @@ subroutine input_data shortwave = 'dEdd' endif + if (tr_snow .and. trim(shortwave) /= 'dEdd') then + write (nu_diag,*) 'WARNING: snow grain radius activated but' + write (nu_diag,*) 'WARNING: dEdd shortwave is not.' + endif + rfracmin = min(max(rfracmin,c0),c1) rfracmax = min(max(rfracmax,c0),c1) From 19c44f4ccd423f14f250674d73805ba98f4155ed Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 26 Feb 2021 20:36:57 -0700 Subject: [PATCH 13/47] add meltsliq to ponds, clean up --- columnphysics/icepack_meltpond_cesm.F90 | 31 ++++--- columnphysics/icepack_meltpond_lvl.F90 | 24 ++++-- columnphysics/icepack_snow.F90 | 12 +-- columnphysics/icepack_therm_vertical.F90 | 101 ++++++++++++++--------- 4 files changed, 101 insertions(+), 67 deletions(-) diff --git a/columnphysics/icepack_meltpond_cesm.F90 b/columnphysics/icepack_meltpond_cesm.F90 index 54e5ad7ad..d7756aa3b 100644 --- a/columnphysics/icepack_meltpond_cesm.F90 +++ b/columnphysics/icepack_meltpond_cesm.F90 @@ -16,7 +16,7 @@ module icepack_meltpond_cesm use icepack_kinds use icepack_parameters, only: c0, c1, c2, p01, puny - use icepack_parameters, only: rhofresh, rhoi, rhos, Timelt + use icepack_parameters, only: rhofresh, rhoi, rhos, Timelt, pndaspect, use_smliq_pnd use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -32,19 +32,19 @@ module icepack_meltpond_cesm !======================================================================= subroutine compute_ponds_cesm(dt, hi_min, & - pndaspect, & rfrac, meltt, & melts, frain, & - aicen, vicen, & - Tsfcn, apnd, hpnd) + aicen, vicen, & + Tsfcn, apnd, hpnd, & + meltsliqn) real (kind=dbl_kind), intent(in) :: & dt, & ! time step (s) - hi_min, & ! minimum ice thickness allowed for thermo (m) - pndaspect ! ratio of pond depth to pond fraction + hi_min ! minimum ice thickness allowed for thermo (m) real (kind=dbl_kind), intent(in) :: & - rfrac, & ! water fraction retained for melt ponds + meltsliqn, & ! liquid input from snow liquid tracer + rfrac, & ! water fraction retained for melt ponds meltt, & melts, & frain, & @@ -104,11 +104,18 @@ subroutine compute_ponds_cesm(dt, hi_min, & !----------------------------------------------------------- ! Update pond volume !----------------------------------------------------------- - volpn = volpn & - + rfrac/rhofresh*(meltt*rhoi & - + melts*rhos & - + frain* dt)& - * aicen + if (use_smliq_pnd) then + volpn = volpn & + + rfrac/rhofresh*(meltt*rhoi & + + meltsliqn) & + * aicen + else + volpn = volpn & + + rfrac/rhofresh*(meltt*rhoi & + + melts*rhos & + + frain* dt)& + * aicen + endif !----------------------------------------------------------- ! Shrink pond volume under freezing conditions diff --git a/columnphysics/icepack_meltpond_lvl.F90 b/columnphysics/icepack_meltpond_lvl.F90 index c624ffcba..11a9da1f1 100644 --- a/columnphysics/icepack_meltpond_lvl.F90 +++ b/columnphysics/icepack_meltpond_lvl.F90 @@ -17,7 +17,7 @@ module icepack_meltpond_lvl use icepack_kinds use icepack_parameters, only: c0, c1, c2, c10, p01, p5, puny use icepack_parameters, only: viscosity_dyn, rhoi, rhos, rhow, Timelt, Tffresh, Lfresh - use icepack_parameters, only: gravit, depressT, rhofresh, kice + use icepack_parameters, only: gravit, depressT, rhofresh, kice, pndaspect, use_smliq_pnd use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -35,14 +35,15 @@ module icepack_meltpond_lvl subroutine compute_ponds_lvl(dt, nilyr, & ktherm, & hi_min, dpscale, & - frzpnd, pndaspect, & + frzpnd, & rfrac, meltt, melts, & frain, Tair, fsurfn,& dhs, ffrac, & aicen, vicen, vsnon, & qicen, sicen, & Tsfcn, alvl, & - apnd, hpnd, ipnd) + apnd, hpnd, ipnd, & + meltsliqn) integer (kind=int_kind), intent(in) :: & nilyr, & ! number of ice layers @@ -51,8 +52,7 @@ subroutine compute_ponds_lvl(dt, nilyr, & real (kind=dbl_kind), intent(in) :: & dt, & ! time step (s) hi_min, & ! minimum ice thickness allowed for thermo (m) - dpscale, & ! alter e-folding time scale for flushing - pndaspect ! ratio of pond depth to pond fraction + dpscale ! alter e-folding time scale for flushing character (len=char_len), intent(in) :: & frzpnd ! pond refreezing parameterization @@ -69,7 +69,8 @@ subroutine compute_ponds_lvl(dt, nilyr, & fsurfn,& ! atm-ice surface heat flux (W/m2) aicen, & ! ice area fraction vicen, & ! ice volume (m) - vsnon ! snow volume (m) + vsnon, & ! snow volume (m) + meltsliqn ! liquid contribution to meltponds in dt (kg/m^2) real (kind=dbl_kind), & intent(inout) :: & @@ -154,9 +155,14 @@ subroutine compute_ponds_lvl(dt, nilyr, & ! update pond volume !----------------------------------------------------------- ! add melt water - dvn = rfrac/rhofresh*(meltt*rhoi & - + melts*rhos & - + frain* dt)*aicen + if (use_smliq_pnd) then + dvn = rfrac/rhofresh*(meltt*rhoi & + + meltsliqn)*aicen + else + dvn = rfrac/rhofresh*(meltt*rhoi & + + melts*rhos & + + frain* dt)*aicen + endif ! shrink pond volume under freezing conditions if (trim(frzpnd) == 'cesm') then diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index cb3fb9577..bc376b434 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -152,14 +152,10 @@ subroutine icepack_step_snow(dt, nilyr, & tmp2 = rhos*vsno + fresh*dt ! check conservation -! if (abs(tmp1-tmp2)>puny) then -! write(warning,*) ' ' -! call add_warning(warning) -! write(warning,*)'tmp1 ne tmp2',tmp1, tmp2 -! call add_warning(warning) -! stop_label ='snow redistribution error' -! l_stop = .true. -! endif + if (abs(tmp1-tmp2)>puny) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: snow redistribution') + endif !----------------------------------------------------------------- ! Adjust snow grain radius diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index f1cd65bc5..71ebac435 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -25,7 +25,7 @@ module icepack_therm_vertical use icepack_parameters, only: cp_ocn, rhow, rhoi, rhos, Lfresh, rhofresh, ice_ref_salinity use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc, rsnw_fall, rsnw_tmax use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair - use icepack_parameters, only: rfracmin, rfracmax, pndaspect, dpscale, frzpnd + use icepack_parameters, only: rfracmin, rfracmax, dpscale, frzpnd use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso @@ -248,8 +248,8 @@ subroutine thermo_vertical (nilyr, nslyr, & flwoutn = c0 evapn = c0 - evapsn = c0 - evapin = c0 + evapsn = c0 + evapin = c0 freshn = c0 fsaltn = c0 fhocnn = c0 @@ -263,6 +263,7 @@ subroutine thermo_vertical (nilyr, nslyr, & dsnow = c0 zTsn(:) = c0 zTin(:) = c0 + meltsliq= c0 if (calc_Tsfc) then fsensn = c0 @@ -1192,8 +1193,10 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(k) = hslyr smicetot(k) = c0 smliqtot(k) = c0 - smicetot(k) = dzs(k) * smice(k) - smliqtot(k) = dzs(k) * smliq(k) + if (tr_snow) then + smicetot(k) = dzs(k) * smice(k) + smliqtot(k) = dzs(k) * smliq(k) + endif enddo do k = 1, nilyr @@ -1509,18 +1512,19 @@ subroutine thickness_changes (nilyr, nslyr, & if (hstot > c0) then zqsn(1) = (dzs(1) * zqsn(1) & + hsn_new * zqsnew) / hstot - zqsn(1) = min(zqsn(1), -rhos*Lfresh) ! avoid roundoff errors - - ! ice mass in snow due to snowfall - ! new snow density = rhos for now !echmod - fix this - smicetot(1) = smicetot(1) + hsn_new * rhos ! kg/m^2 + zqsn(1) = min(zqsn(1), zqsnew) ! avoid roundoff errors + if (tr_snow) then + ! ice mass in snow due to snowfall + ! new snow density = rhos for now !echmod - fix this + smicetot(1) = smicetot(1) + hsn_new * rhos ! kg/m^2 + endif dzs(1) = hstot endif endif !---!----------------------------------------------------------------- -!---! Add rain at top surface (only to liquid tracer) +!---! Add rain at top surface (only to liquid tracer) !---!----------------------------------------------------------------- smliqtot(1) = smliqtot(1) + frain*dt @@ -2560,6 +2564,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & congeln(n) = c0 snoicen(n) = c0 dsnown (n) = c0 + meltsliqn(n) = c0 Trefn = c0 Qrefn = c0 @@ -2682,7 +2687,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & yday=yday, dsnow=dsnown (n), & prescribed_ice=prescribed_ice) - if (icepack_warnings_aborted(subname)) then + if (icepack_warnings_aborted(subname)) then call icepack_warnings_add(subname//' ice: Vertical thermo error: ') return endif @@ -2734,7 +2739,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & endif endif ! aicen_init - if (tr_snow .and. use_smliq_pnd) then + if (use_smliq_pnd) then call drain_snow (dt = dt, nslyr = nslyr, & vsnon = vsnon(n), aicen = aicen(n), & smice = l_smice(:,n), smliq = l_smliq(:,n), & @@ -2753,32 +2758,47 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & if (tr_pond_cesm) then rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n) - call compute_ponds_cesm(dt, hi_min, & - pndaspect, rfrac, & - melttn(n), meltsn(n), & - frain, & - aicen (n), vicen (n), & - Tsfc (n), & - apnd (n), hpnd (n)) + call compute_ponds_cesm(dt=dt, & + hi_min=hi_min, & + rfrac=rfrac, & + meltt=melttn(n), & + melts=meltsn(n), & + frain=frain, & + aicen=aicen (n), & + vicen=vicen (n), & + Tsfcn=Tsfc (n), & + apnd=apnd (n), & + hpnd=hpnd (n), & + meltsliqn=l_meltsliq(n)) if (icepack_warnings_aborted(subname)) return elseif (tr_pond_lvl) then rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n) - call compute_ponds_lvl(dt, nilyr, & - ktherm, & - hi_min, & - dpscale, frzpnd, & - pndaspect, rfrac, & - melttn(n), meltsn(n), & - frain, Tair, & - fsurfn(n), & - dhsn (n), ffracn(n), & - aicen (n), vicen (n), & - vsnon (n), & - zqin(:,n), zSin(:,n), & - Tsfc (n), alvl (n), & - apnd (n), hpnd (n), & - ipnd (n)) + call compute_ponds_lvl (dt=dt, & + nilyr=nilyr, & + ktherm=ktherm, & + hi_min=hi_min, & + dpscale=dpscale, & + frzpnd=frzpnd, & + rfrac=rfrac, & + meltt=melttn (n), & + melts=meltsn (n), & + frain=frain, & + Tair=Tair, & + fsurfn=fsurfn(n), & + dhs=dhsn (n), & + ffrac=ffracn (n), & + aicen=aicen (n), & + vicen=vicen (n), & + vsnon=vsnon (n), & + qicen=zqin (:,n), & + sicen=zSin (:,n), & + Tsfcn=Tsfc (n), & + alvl=alvl (n), & + apnd=apnd (n), & + hpnd=hpnd (n), & + ipnd=ipnd (n), & + meltsliqn=l_meltsliq(n)) if (icepack_warnings_aborted(subname)) return elseif (tr_pond_topo) then @@ -2787,9 +2807,14 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & ! collect liquid water in ponds ! assume salt still runs off rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n) - pond = rfrac/rhofresh * (melttn(n)*rhoi & - + meltsn(n)*rhos & - + frain *dt) + if (use_smliq_pnd) then + pond = rfrac/rhofresh * (melttn(n)*rhoi & + + l_meltsliq(n)) + else + pond = rfrac/rhofresh * (melttn(n)*rhoi & + + meltsn(n)*rhos & + + frain *dt) + endif ! if pond does not exist, create new pond over full ice area ! otherwise increase pond depth without changing pond area From ffef53404d86f2fc41fe8ee579425b5055cd2182 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 26 Feb 2021 22:05:56 -0700 Subject: [PATCH 14/47] adding snwgrain namelist flag --- columnphysics/icepack_parameters.F90 | 16 +++++--- columnphysics/icepack_shortwave.F90 | 16 ++++---- columnphysics/icepack_snow.F90 | 39 ++++++++++--------- columnphysics/icepack_therm_vertical.F90 | 19 ++++----- configuration/driver/icedrv_init.F90 | 15 ++++--- configuration/driver/icedrv_step.F90 | 3 +- configuration/scripts/icepack_in | 1 + .../scripts/options/set_nml.snwgrain | 2 + 8 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 configuration/scripts/options/set_nml.snwgrain diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index 372d07874..c9f0d5d2d 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -319,7 +319,8 @@ module icepack_parameters snwredist = 'none' ! type of snow redistribution logical (kind=log_kind), public :: & - use_smliq_pnd = .false. ! use liquid in snow for ponds + use_smliq_pnd = .false. , & ! use liquid in snow for ponds + snwgrain = .false. ! snow metamorphosis real (kind=dbl_kind), public :: & rsnw_fall = 54.526_dbl_kind, & ! radius of new snow (10^-6 m) @@ -450,7 +451,7 @@ subroutine icepack_init_parameters( & fr_dFe_in, k_nitrif_in, t_iron_conv_in, max_loss_in, & max_dfe_doc1_in, fr_resp_s_in, conserv_check_in, & y_sk_DMS_in, t_sk_conv_in, t_sk_ox_in, frazil_scav_in, & - sw_redist_in, sw_frac_in, sw_dtemp_in, & + sw_redist_in, sw_frac_in, sw_dtemp_in, snwgrain_in, & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & rhosnew_in, rhosmin_in, rhosmax_in, windmin_in, drhosdwind_in, & snwlvlfac_in, isnw_T_in, isnw_Tgrd_in, isnw_rhos_in, & @@ -758,7 +759,8 @@ subroutine icepack_init_parameters( & snwredist_in ! type of snow redistribution logical (kind=log_kind), intent(in), optional :: & - use_smliq_pnd_in ! use liquid in snow for ponds + use_smliq_pnd_in, &! use liquid in snow for ponds + snwgrain_in ! snow metamorphosis real (kind=dbl_kind), intent(in), optional :: & rsnw_fall_in, & ! radius of new snow (10^-6 m) @@ -894,6 +896,7 @@ subroutine icepack_init_parameters( & if (present(hs1_in) ) hs1 = hs1_in if (present(hp1_in) ) hp1 = hp1_in if (present(snwredist_in) ) snwredist = snwredist_in + if (present(snwgrain_in) ) snwgrain = snwgrain_in if (present(use_smliq_pnd_in) ) use_smliq_pnd = use_smliq_pnd_in if (present(rsnw_fall_in) ) rsnw_fall = rsnw_fall_in if (present(rsnw_tmax_in) ) rsnw_tmax = rsnw_tmax_in @@ -1000,7 +1003,7 @@ subroutine icepack_query_parameters( & fr_mort2min_out, fr_resp_s_out, fr_dFe_out, & k_nitrif_out, t_iron_conv_out, max_loss_out, max_dfe_doc1_out, & y_sk_DMS_out, t_sk_conv_out, t_sk_ox_out, frazil_scav_out, & - sw_redist_out, sw_frac_out, sw_dtemp_out, & + sw_redist_out, sw_frac_out, sw_dtemp_out, snwgrain_out, & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & rhosnew_out, rhosmin_out, rhosmax_out, windmin_out, drhosdwind_out, & snwlvlfac_out, isnw_T_out, isnw_Tgrd_out, isnw_rhos_out, & @@ -1317,7 +1320,8 @@ subroutine icepack_query_parameters( & snwredist_out ! type of snow redistribution logical (kind=log_kind), intent(out), optional :: & - use_smliq_pnd_out ! use liquid in snow for ponds + use_smliq_pnd_out, &! use liquid in snow for ponds + snwgrain_out ! snow metamorphosis real (kind=dbl_kind), intent(out), optional :: & rsnw_fall_out, & ! radius of new snow (10^-6 m) @@ -1493,6 +1497,7 @@ subroutine icepack_query_parameters( & if (present(hs1_out) ) hs1_out = hs1 if (present(hp1_out) ) hp1_out = hp1 if (present(snwredist_out) ) snwredist_out = snwredist + if (present(snwgrain_out) ) snwgrain_out = snwgrain if (present(use_smliq_pnd_out) ) use_smliq_pnd_out= use_smliq_pnd if (present(rsnw_fall_out) ) rsnw_fall_out = rsnw_fall if (present(rsnw_tmax_out) ) rsnw_tmax_out = rsnw_tmax @@ -1689,6 +1694,7 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " hs1 = ", hs1 write(iounit,*) " hp1 = ", hp1 write(iounit,*) " snwredist = ", snwredist + write(iounit,*) " snwgrain = ", snwgrain write(iounit,*) " use_smliq_pnd = ", use_smliq_pnd write(iounit,*) " rsnw_fall = ", rsnw_fall write(iounit,*) " rsnw_tmax = ", rsnw_tmax diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 2d88ffadb..b88311e5e 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -45,12 +45,12 @@ module icepack_shortwave use icepack_parameters, only: p01, p1, p15, p25, p5, p75, puny use icepack_parameters, only: albocn, Timelt, snowpatch, awtvdr, awtidr, awtvdf, awtidf use icepack_parameters, only: kappav, hs_min, rhofresh, rhos, nspint, rsnw_fall, snwredist - use icepack_parameters, only: hi_ssl, hs_ssl, min_bgc, sk_l, snwlvlfac + use icepack_parameters, only: hi_ssl, hs_ssl, min_bgc, sk_l, snwlvlfac, snwgrain use icepack_parameters, only: z_tracers, skl_bgc, calc_tsfc, shortwave, kalg, heat_capacity use icepack_parameters, only: r_ice, r_pnd, r_snw, dt_mlt, rsnw_mlt, hs0, hs1, hp1 use icepack_parameters, only: pndaspect, albedo_type, albicev, albicei, albsnowv, albsnowi, ahmax use icepack_tracers, only: ntrcr, nbtrcr_sw - use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow + use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo use icepack_tracers, only: tr_bgc_N, tr_aero use icepack_tracers, only: nt_bgc_N, nt_zaero, tr_bgc_N use icepack_tracers, only: tr_zaero, nlt_chl_sw, nlt_zaero_sw @@ -882,7 +882,7 @@ subroutine run_dEdd(dt, ncat, & trcrn_bgcsw ! zaerosols (kg/m^3) + chlorophyll on shorthwave grid real(kind=dbl_kind), dimension(:), intent(inout) :: & - rsnw_dEddn, & ! snow grain radius if .not. tr_rsnw (10^-6 m) + rsnw_dEddn, & ! constant snow grain radius (10^-6 m) ffracn,& ! fraction of fsurfn used to melt ipond dhsn ! depth difference for snow on sea ice and pond ice @@ -1183,7 +1183,7 @@ subroutine run_dEdd(dt, ncat, & if (icepack_warnings_aborted(subname)) return - if (.not. tr_snow) then + if (.not. snwgrain) then rnslyr = c1/max(c1,(real(nslyr,kind=dbl_kind))) do k = 1,nslyr rsnw_dEddn(n) = rsnw_dEddn(n) + rsnwn(k)*rnslyr @@ -3665,7 +3665,7 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & if (hs0 > puny) fs = min(hs/hs0, c1) endif - if (tr_snow) then ! use snow grain tracer + if (snwgrain) then ! use snow grain tracer do ks = 1, nslyr rsnw(ks) = max(rsnw_fall,rsnow(ks)) @@ -3692,7 +3692,7 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & rsnw(ks) = min(rsnw(ks), rsnw_mlt) enddo ! ks - endif ! tr_snow + endif ! snwgrain end subroutine shortwave_dEdd_set_snow @@ -4173,7 +4173,7 @@ subroutine icepack_step_radiation (dt, ncat, & rsnow ! snow grain radius tracer (10^-6 m) real(kind=dbl_kind), dimension(:), intent(inout), optional :: & - rsnw_dEddn ! snow grain radius if .not. tr_snow (10^-6 m) + rsnw_dEddn ! constant snow grain radius (10^-6 m) logical (kind=log_kind), optional :: & initonly ! flag to indicate init only, default is false @@ -4197,7 +4197,7 @@ subroutine icepack_step_radiation (dt, ncat, & l_fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) l_fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) l_fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) - l_rsnw_dEddn ! snow grain radius if .not. tr_snow (10^-6 m) + l_rsnw_dEddn ! constant snow grain radius (10^-6 m) real (kind=dbl_kind), dimension(:,:), allocatable :: & l_rsnow ! snow grain radius tracer (10^-6 m) diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index bc376b434..b9e93e3d2 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -9,7 +9,7 @@ module icepack_snow use icepack_kinds use icepack_parameters, only: puny, p1, p5, c0, c1, c4, c10, c100, pi - use icepack_parameters, only: rhos, rhow, rhoi, rhofresh + use icepack_parameters, only: rhos, rhow, rhoi, rhofresh, snwgrain use icepack_parameters, only: snwlvlfac, Tffresh, cp_ice, Lfresh use icepack_parameters, only: snwredist, rsnw_fall, rsnw_tmax, rhosnew use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind @@ -126,7 +126,7 @@ subroutine icepack_step_snow(dt, nilyr, & smice, smliq, & rhos_effn, rhos_eff, & rhos_cmpn, rhos_cmp) - +print*,'A smliq',smliq !----------------------------------------------------------------- ! Redistribute snow based on wind !----------------------------------------------------------------- @@ -161,23 +161,26 @@ subroutine icepack_step_snow(dt, nilyr, & ! Adjust snow grain radius !----------------------------------------------------------------- - do n = 1, ncat - zTin1(n) = c0 - hsn (n) = c0 - hin (n) = c0 - if (aicen(n) > puny) then - zTin1(n) = icepack_ice_temperature(zqin1(n), zSin1(n)) - hsn(n) = vsnon(n)/aicen(n) - hin(n) = vicen(n)/aicen(n) - endif - enddo + if (snwgrain) then + do n = 1, ncat + zTin1(n) = c0 + hsn (n) = c0 + hin (n) = c0 + if (aicen(n) > puny) then + zTin1(n) = icepack_ice_temperature(zqin1(n), zSin1(n)) + hsn(n) = vsnon(n)/aicen(n) + hin(n) = vicen(n)/aicen(n) + endif + enddo - call update_snow_radius (dt, ncat, & - nslyr, nilyr, & - rsnw, hin, & - Tsfc, zTin1, & - hsn, zqsn, & - smice, smliq) + call update_snow_radius (dt, ncat, & + nslyr, nilyr, & + rsnw, hin, & + Tsfc, zTin1, & + hsn, zqsn, & + smice, smliq) +print*,'B smliq',smliq + endif end subroutine icepack_step_snow diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 71ebac435..ab30a09df 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -25,7 +25,7 @@ module icepack_therm_vertical use icepack_parameters, only: cp_ocn, rhow, rhoi, rhos, Lfresh, rhofresh, ice_ref_salinity use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc, rsnw_fall, rsnw_tmax use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair - use icepack_parameters, only: rfracmin, rfracmax, dpscale, frzpnd + use icepack_parameters, only: rfracmin, rfracmax, dpscale, frzpnd, snwgrain use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso @@ -1514,7 +1514,7 @@ subroutine thickness_changes (nilyr, nslyr, & + hsn_new * zqsnew) / hstot zqsn(1) = min(zqsn(1), zqsnew) ! avoid roundoff errors - if (tr_snow) then + if (tr_snow) then !echmod - is tr_snow needed? ! ice mass in snow due to snowfall ! new snow density = rhos for now !echmod - fix this smicetot(1) = smicetot(1) + hsn_new * rhos ! kg/m^2 @@ -1549,7 +1549,7 @@ subroutine thickness_changes (nilyr, nslyr, & ! Incorporate new snow for snow grain radius !------------------------------------------------------------------- - if (tr_snow .and. hsn_new > c0) then + if (snwgrain .and. hsn_new > c0) then tmp1 = max(c0, dzs(1) - hsn_new) rsnw(1) = (rsnw_fall * hsn_new + rsnw(1) * tmp1) & / max( hsn_new + tmp1, puny) @@ -1678,11 +1678,12 @@ subroutine thickness_changes (nilyr, nslyr, & zs1, zs2, & hslyr, hsn, & zqsn) - if (tr_snow) then + if (snwgrain) & call adjust_enthalpy (nslyr, & zs1(:), zs2(:), & hslyr, hsn, & rsnw(:)) + if (tr_snow) then call adjust_enthalpy (nslyr, & zs1(:), zs2(:), & hslyr, hsn, & @@ -1706,11 +1707,11 @@ subroutine thickness_changes (nilyr, nslyr, & fhocnn = fhocnn & + zqsn(k)*hsn/(real(nslyr,kind=dbl_kind)*dt) zqsn(k) = -rhos*Lfresh - - meltsliq = meltsliq + smicetot(k) ! add to meltponds - smice(k) = c0 - smliq(k) = c0 - + if (tr_snow) then + meltsliq = meltsliq + smicetot(k) ! add to meltponds + smice(k) = c0 + smliq(k) = c0 + endif hslyr = c0 endif enddo diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index df72341b6..0e024142e 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -98,7 +98,7 @@ subroutine input_data character (len=char_len) :: shortwave, albedo_type, conduct, fbot_xfer_type, & tfrz_option, frzpnd, atmbndy, wave_spec_type, snwredist - logical (kind=log_kind) :: sw_redist, use_smliq_pnd + logical (kind=log_kind) :: sw_redist, use_smliq_pnd, snwgrain real (kind=dbl_kind) :: sw_frac, sw_dtemp ! Flux convergence tolerance @@ -157,9 +157,9 @@ subroutine input_data hp1 namelist /snow_nml/ & - snwredist, use_smliq_pnd, rsnw_fall, rsnw_tmax, & + snwredist, snwgrain, rsnw_fall, rsnw_tmax, & rhosnew, rhosmin, rhosmax, snwlvlfac, & - windmin, drhosdwind + windmin, drhosdwind, use_smliq_pnd namelist /forcing_nml/ & atmbndy, calc_strair, calc_Tsfc, & @@ -221,7 +221,7 @@ subroutine input_data wave_spec_type_out=wave_spec_type, & sw_redist_out=sw_redist, sw_frac_out=sw_frac, sw_dtemp_out=sw_dtemp, & snwredist_out=snwredist, use_smliq_pnd_out=use_smliq_pnd, & - rsnw_fall_out=rsnw_fall, rsnw_tmax_out=rsnw_tmax, & + snwgrain_out=snwgrain, rsnw_fall_out=rsnw_fall, rsnw_tmax_out=rsnw_tmax, & rhosnew_out=rhosnew, rhosmin_out = rhosmin, rhosmax_out=rhosmax, & windmin_out=windmin, drhosdwind_out=drhosdwind, snwlvlfac_out=snwlvlfac) @@ -439,6 +439,10 @@ subroutine input_data write (nu_diag,*) 'WARNING: snow tracers are not active' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif + if (snwgrain .and. .not. tr_snow) then + write (nu_diag,*) 'WARNING: snwgrain=T but tr_snow=F' + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif if (tr_iso .and. n_iso==0) then write (nu_diag,*) 'WARNING: isotopes activated but' @@ -603,6 +607,7 @@ subroutine input_data if (tr_snow) then write(nu_diag,1030) ' snwredist = ', snwredist + write(nu_diag,1010) ' snwgrain = ', snwgrain write(nu_diag,1010) ' use_smliq_pnd = ', use_smliq_pnd write(nu_diag,1000) ' rsnw_fall = ', rsnw_fall write(nu_diag,1000) ' rsnw_tmax = ', rsnw_tmax @@ -851,7 +856,7 @@ subroutine input_data wave_spec_type_in=wave_spec_type, wave_spec_in=wave_spec, & sw_redist_in=sw_redist, sw_frac_in=sw_frac, sw_dtemp_in=sw_dtemp, & snwredist_in=snwredist, use_smliq_pnd_in=use_smliq_pnd, & - rsnw_fall_in=rsnw_fall, rsnw_tmax_in=rsnw_tmax, & + snwgrain_in=snwgrain, rsnw_fall_in=rsnw_fall, rsnw_tmax_in=rsnw_tmax, & rhosnew_in=rhosnew, rhosmin_in=rhosmin, rhosmax_in=rhosmax, & windmin_in=windmin, drhosdwind_in=drhosdwind, snwlvlfac_in=snwlvlfac) call icepack_init_tracer_sizes(ntrcr_in=ntrcr, & diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index fca656ec9..ebadbe1af 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -231,6 +231,7 @@ subroutine step_therm1 (dt) enddo ! i do i = 1, nx +!echmod do i = 3,3 if (tr_aero) then ! trcrn(nt_aero) has units kg/m^3 do n=1,ncat @@ -254,7 +255,7 @@ subroutine step_therm1 (dt) enddo enddo endif ! tr_iso - +!print*,' driver i', i call icepack_step_therm1(dt=dt, ncat=ncat, nilyr=nilyr, nslyr=nslyr, & aicen_init = aicen_init(i,:), & vicen_init = vicen_init(i,:), & diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 936bc7f82..6679f9e52 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -81,6 +81,7 @@ &snow_nml snwredist = 'none' + snwgrain = .false. use_smliq_pnd = .false. rsnw_fall = 54.526 rsnw_tmax = 1500.0 diff --git a/configuration/scripts/options/set_nml.snwgrain b/configuration/scripts/options/set_nml.snwgrain new file mode 100644 index 000000000..4928dc178 --- /dev/null +++ b/configuration/scripts/options/set_nml.snwgrain @@ -0,0 +1,2 @@ +tr_snow = .true. +snwgrain = .true. From bc9b29d927d257acceebd2fa402eab0c215bc2de Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Mon, 15 Mar 2021 14:08:57 -0600 Subject: [PATCH 15/47] Bug fixes from https://github.com/MPAS-Dev/MPAS-Model/pull/314 --- columnphysics/icepack_algae.F90 | 1 + columnphysics/icepack_snow.F90 | 2 +- columnphysics/icepack_zbgc_shared.F90 | 8 +++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/columnphysics/icepack_algae.F90 b/columnphysics/icepack_algae.F90 index 90a4376aa..c22fa8d1d 100644 --- a/columnphysics/icepack_algae.F90 +++ b/columnphysics/icepack_algae.F90 @@ -332,6 +332,7 @@ subroutine zbio (dt, nblyr, & if (icepack_warnings_aborted(subname)) return call merge_bgc_fluxes (dt, nblyr, & + nslyr, & bio_index, n_algae, & nbtrcr, aicen, & vicen, vsnon, & diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index b9e93e3d2..c695df192 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -25,7 +25,7 @@ module icepack_snow real (kind=dbl_kind), parameter, public :: & S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) - S_wet= 0.422_dbl_kind ! (um^3/s) wet metamorphism parameters + S_wet= 4.22e-5_dbl_kind ! (um^3/s) wet metamorphism parameters !======================================================================= diff --git a/columnphysics/icepack_zbgc_shared.F90 b/columnphysics/icepack_zbgc_shared.F90 index e542b8386..68200b621 100644 --- a/columnphysics/icepack_zbgc_shared.F90 +++ b/columnphysics/icepack_zbgc_shared.F90 @@ -553,6 +553,7 @@ end subroutine regrid_stationary ! for z layer biogeochemistry ! subroutine merge_bgc_fluxes (dt, nblyr, & + nslyr, & bio_index, n_algae, & nbtrcr, aicen, & vicen, vsnon, & @@ -571,8 +572,9 @@ subroutine merge_bgc_fluxes (dt, nblyr, & dt ! timestep (s) integer (kind=int_kind), intent(in) :: & - nblyr, & - n_algae, & ! + nblyr , & ! number of bio layers + nslyr , & ! number of snow layers + n_algae , & ! number of algal tracers nbtrcr ! number of biology tracer tracers integer (kind=int_kind), dimension(:), intent(in) :: & @@ -647,7 +649,7 @@ subroutine merge_bgc_fluxes (dt, nblyr, & !----------------------------------------------------------------- ! Merge fluxes !----------------------------------------------------------------- - dvssl = min(p5*vsnon, hs_ssl*aicen) ! snow surface layer + dvssl = min(p5*vsnon/real(nslyr,kind=dbl_kind), hs_ssl*aicen) ! snow surface layer dvint = vsnon - dvssl ! snow interior snow_bio_net(mm) = snow_bio_net(mm) & + trcrn(bio_index(mm)+nblyr+1)*dvssl & From a046165bbeed2a3c68f2c5ef743a3c6e50a5f3b0 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 18 Mar 2021 17:25:55 -0600 Subject: [PATCH 16/47] constrain calculations based on configuration options, add diagnostics, initialize, debug, clean up --- columnphysics/icepack_shortwave.F90 | 4 +- columnphysics/icepack_snow.F90 | 20 ++- columnphysics/icepack_therm_mushy.F90 | 6 +- columnphysics/icepack_therm_vertical.F90 | 160 ++++++++++---------- configuration/driver/icedrv_diagnostics.F90 | 93 +++++++++--- configuration/driver/icedrv_init.F90 | 46 ++++-- configuration/driver/icedrv_step.F90 | 4 +- configuration/scripts/icepack_in | 6 +- 8 files changed, 212 insertions(+), 127 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index b88311e5e..5eeecd6e5 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -1032,7 +1032,7 @@ subroutine run_dEdd(dt, ncat, & elseif (tr_pond_lvl) then hsnlvl = hsn ! initialize - if (trim(snwredist) == '30percentsw') then + if (trim(snwredist) == 'bulk') then hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) ! snow volume over level ice alvl = aicen(n) * alvln(n) @@ -1184,7 +1184,7 @@ subroutine run_dEdd(dt, ncat, & if (icepack_warnings_aborted(subname)) return if (.not. snwgrain) then - rnslyr = c1/max(c1,(real(nslyr,kind=dbl_kind))) + rnslyr = c1/min(c1,(real(nslyr,kind=dbl_kind))) do k = 1,nslyr rsnw_dEddn(n) = rsnw_dEddn(n) + rsnwn(k)*rnslyr enddo diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index c695df192..6d16c4184 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -126,7 +126,7 @@ subroutine icepack_step_snow(dt, nilyr, & smice, smliq, & rhos_effn, rhos_eff, & rhos_cmpn, rhos_cmp) -print*,'A smliq',smliq + !----------------------------------------------------------------- ! Redistribute snow based on wind !----------------------------------------------------------------- @@ -179,7 +179,6 @@ subroutine icepack_step_snow(dt, nilyr, & Tsfc, zTin1, & hsn, zqsn, & smice, smliq) -print*,'B smliq',smliq endif end subroutine icepack_step_snow @@ -231,11 +230,15 @@ subroutine snow_effective_density(nslyr, ncat, & ! Initialize effective snow density (compaction) for new snow !----------------------------------------------------------------- - do n = 1, ncat - do k = 1, nslyr - if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew + if (trim(snwredist) /= 'none') then + do n = 1, ncat + do k = 1, nslyr + if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew + enddo enddo - enddo + else + rhos_cmpn(:,:) = rhos + endif !----------------------------------------------------------------- ! Compute average effective density of snow @@ -253,6 +256,11 @@ subroutine snow_effective_density(nslyr, ncat, & rhos_eff = rhos_eff/(vsno*real(nslyr,kind=dbl_kind)) rhos_cmp = rhos_cmp/(vsno*real(nslyr,kind=dbl_kind)) + else + + rhos_eff = rhos ! default to standard value + rhos_cmp = rhos + endif ! vsno end subroutine snow_effective_density diff --git a/columnphysics/icepack_therm_mushy.F90 b/columnphysics/icepack_therm_mushy.F90 index 9c284455e..639303fbe 100644 --- a/columnphysics/icepack_therm_mushy.F90 +++ b/columnphysics/icepack_therm_mushy.F90 @@ -6,7 +6,7 @@ module icepack_therm_mushy use icepack_parameters, only: c0, c1, c2, c8, c10 use icepack_parameters, only: p01, p05, p1, p2, p5, pi, bignum, puny use icepack_parameters, only: viscosity_dyn, rhow, rhoi, rhos, cp_ocn, cp_ice, Lfresh, gravit - use icepack_parameters, only: hs_min + use icepack_parameters, only: hs_min, snwgrain use icepack_parameters, only: a_rapid_mode, Rac_rapid_mode use icepack_parameters, only: aspect_rapid_mode, dSdt_slow_mode, phi_c_slow_mode use icepack_parameters, only: sw_redist, sw_frac, sw_dtemp @@ -16,7 +16,7 @@ module icepack_therm_mushy use icepack_mushy_physics, only: temperature_snow, temperature_mush_liquid_fraction use icepack_mushy_physics, only: liquidus_brine_salinity_mush, liquidus_temperature_mush use icepack_mushy_physics, only: conductivity_mush_array, conductivity_snow_array - use icepack_tracers, only: tr_pond, tr_snow + use icepack_tracers, only: tr_pond use icepack_therm_shared, only: surface_heat_flux, dsurface_heat_flux_dTsf use icepack_therm_shared, only: ferrmax use icepack_warnings, only: warnstr, icepack_warnings_add @@ -3343,7 +3343,7 @@ subroutine flood_ice(hsn, hin, & call update_vertical_tracers_snow(nslyr, zqsn, hslyr, hslyr2) if (icepack_warnings_aborted(subname)) return - if (tr_snow .and. hslyr2 > puny) then + if (snwgrain .and. hslyr2 > puny) then call update_vertical_tracers_snow(nslyr, smice, hslyr, hslyr2) call update_vertical_tracers_snow(nslyr, smliq, hslyr, hslyr2) if (icepack_warnings_aborted(subname)) return diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index ab30a09df..886b74d20 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -25,8 +25,8 @@ module icepack_therm_vertical use icepack_parameters, only: cp_ocn, rhow, rhoi, rhos, Lfresh, rhofresh, ice_ref_salinity use icepack_parameters, only: ktherm, heat_capacity, calc_Tsfc, rsnw_fall, rsnw_tmax use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair - use icepack_parameters, only: rfracmin, rfracmax, dpscale, frzpnd, snwgrain - use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd + use icepack_parameters, only: rfracmin, rfracmax, dpscale, frzpnd, snwgrain, snwlvlfac + use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd, snwredist use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow @@ -932,65 +932,53 @@ subroutine init_vertical_profile(nilyr, nslyr, & !----------------------------------------------------------------- if (tice_high .and. heat_capacity) then - - if (l_brine) then - Tmax = Tmlts(k) - else ! fresh ice - Tmax = -zqin(k)*puny/(rhos*cp_ice*vicen) - endif - - if (zTin(k) > Tmax) then - write(warnstr,*) ' ' - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'Starting thermo, T > Tmax, layer', k - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'k:', k - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zTin =',zTin(k),', Tmax=',Tmax - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zSin =',zSin(k) - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'hin =',hin - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zqin =',zqin(k) - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'qmlt=',enthalpy_of_melting(zSin(k)) - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'Tmlt=',Tmlts(k) - call icepack_warnings_add(warnstr) + write(warnstr,*) ' ' + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'Starting thermo, zTin > Tmax, layer', k + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'k:', k + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'zTin =',zTin(k),', Tmax=',Tmax + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'zSin =',zSin(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'hin =',hin + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'zqin =',zqin(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'qmlt=',enthalpy_of_melting(zSin(k)) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'Tmlt=',Tmlts(k) + call icepack_warnings_add(warnstr) - if (ktherm == 2) then - zqin(k) = enthalpy_of_melting(zSin(k)) - c1 - zTin(k) = icepack_mushy_temperature_mush(zqin(k),zSin(k)) - write(warnstr,*) subname, 'Corrected quantities' - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zqin=',zqin(k) - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zTin=',zTin(k) - call icepack_warnings_add(warnstr) - else - call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - call icepack_warnings_add(subname//" init_vertical_profile: Starting thermo, T > Tmax, layer" ) - return - endif - endif - endif ! tice_high - - if (tice_low .and. heat_capacity) then - - if (zTin(k) < Tmin) then - write(warnstr,*) ' ' - call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'Starting thermo T < Tmin, layer', k + if (ktherm == 2) then + zqin(k) = enthalpy_of_melting(zSin(k)) - c1 + zTin(k) = icepack_mushy_temperature_mush(zqin(k),zSin(k)) + write(warnstr,*) subname, 'Corrected quantities' call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'zTin =', zTin(k) + write(warnstr,*) subname, 'zqin=',zqin(k) call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'Tmin =', Tmin + write(warnstr,*) subname, 'zTin=',zTin(k) call icepack_warnings_add(warnstr) + else call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - call icepack_warnings_add(subname//" init_vertical_profile: Starting thermo, T < Tmin, layer" ) + call icepack_warnings_add(subname//" init_vertical_profile: Starting thermo, zTin > Tmax, layer" ) return endif + endif ! tice_high + + if (tice_low .and. heat_capacity) then + write(warnstr,*) ' ' + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'Starting thermo T < Tmin, layer', k + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'zTin =', zTin(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'Tmin =', Tmin + call icepack_warnings_add(warnstr) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" init_vertical_profile: Starting thermo, zTin < Tmin, layer" ) + return endif ! tice_low !----------------------------------------------------------------- @@ -1191,12 +1179,8 @@ subroutine thickness_changes (nilyr, nslyr, & do k = 1, nslyr dzs(k) = hslyr - smicetot(k) = c0 - smliqtot(k) = c0 - if (tr_snow) then - smicetot(k) = dzs(k) * smice(k) - smliqtot(k) = dzs(k) * smliq(k) - endif + smicetot(k) = dzs(k) * smice(k) + smliqtot(k) = dzs(k) * smliq(k) enddo do k = 1, nilyr @@ -1222,12 +1206,10 @@ subroutine thickness_changes (nilyr, nslyr, & Ts = (Lfresh + zqsn(k)/rhos) / cp_ice if (Ts > c0) then dhs = cp_ice*Ts*dzs(k) / Lfresh - smice_fsnow = c0 if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs smicetot(k) = smicetot(k) - smice_fsnow ! dhs << dzs smliqtot(k) = smliqtot(k) + smice_fsnow - dzs(k) = dzs(k) - dhs zqsn(k) = -rhos*Lfresh endif @@ -1358,12 +1340,10 @@ subroutine thickness_changes (nilyr, nslyr, & dhs = max(-dzs(k), & -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k)) - smice_fsnow = c0 if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs smicetot(k) = smicetot(k) + smice_fsnow ! -dhs <= dzs smliqtot(k) = smliqtot(k) - smice_fsnow - dzs(k) = dzs(k) + dhs zqsn(k) = -rhos * Lfresh melts = melts - dhs @@ -1546,7 +1526,7 @@ subroutine thickness_changes (nilyr, nslyr, & enddo ! k !------------------------------------------------------------------- - ! Incorporate new snow for snow grain radius + ! Incorporate new snow for snow grain radius in upper layer !------------------------------------------------------------------- if (snwgrain .and. hsn_new > c0) then @@ -1574,7 +1554,7 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- ! Update snow mass tracers, smice and smliq, for uneven layers !------------------------------------------------------------------- - if (tr_snow) then + if (snwgrain) then do k = 1, nslyr meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) if (dzs(k) > c0) then @@ -1678,12 +1658,12 @@ subroutine thickness_changes (nilyr, nslyr, & zs1, zs2, & hslyr, hsn, & zqsn) - if (snwgrain) & + + if (snwgrain) then call adjust_enthalpy (nslyr, & zs1(:), zs2(:), & hslyr, hsn, & rsnw(:)) - if (tr_snow) then call adjust_enthalpy (nslyr, & zs1(:), zs2(:), & hslyr, hsn, & @@ -1707,7 +1687,7 @@ subroutine thickness_changes (nilyr, nslyr, & fhocnn = fhocnn & + zqsn(k)*hsn/(real(nslyr,kind=dbl_kind)*dt) zqsn(k) = -rhos*Lfresh - if (tr_snow) then + if (snwgrain) then meltsliq = meltsliq + smicetot(k) ! add to meltponds smice(k) = c0 smliq(k) = c0 @@ -2105,7 +2085,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & frzmlt , rside , & fside , & fsnow , frain , & - fpond , & + fpond , fsloss , & fsurf , fsurfn , & fcondtop , fcondtopn , & fcondbot , fcondbotn , & @@ -2244,10 +2224,11 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & frz_onset ! day of year that freezing begins (congel or frazil) real (kind=dbl_kind), intent(inout), optional :: & - fswthru_vdr , & ! vis dir shortwave penetrating to ocean (W/m^2) - fswthru_vdf , & ! vis dif shortwave penetrating to ocean (W/m^2) - fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) - fswthru_idf ! nir dif shortwave penetrating to ocean (W/m^2) + fswthru_vdr , & ! vis dir shortwave penetrating to ocean (W/m^2) + fswthru_vdf , & ! vis dif shortwave penetrating to ocean (W/m^2) + fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) + fswthru_idf , & ! nir dif shortwave penetrating to ocean (W/m^2) + fsloss ! fraction of snow lost to leads real (kind=dbl_kind), dimension(:), optional, intent(inout) :: & Qa_iso , & ! isotope specific humidity (kg/kg) @@ -2378,6 +2359,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_smliq ! mass of liquid in snow (kg/m^2) real (kind=dbl_kind) :: & + l_fsloss , & ! fraction of snow lost to leads l_HDO_ocn , & ! local ocean concentration of HDO (kg/kg) l_H2_16O_ocn, & ! local ocean concentration of H2_16O (kg/kg) l_H2_18O_ocn ! local ocean concentration of H2_18O (kg/kg) @@ -2459,6 +2441,9 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_fiso_evap = c0 endif + l_fsloss = c0 + if (present(fsloss) ) l_fsloss = fsloss + l_HDO_ocn = c0 if (present(HDO_ocn) ) l_HDO_ocn = HDO_ocn @@ -2501,7 +2486,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & if (present(meltsliqn)) l_meltsliq = meltsliqn allocate(l_rsnw(nslyr,ncat)) - l_rsnw = c0 ! echmod: this should be the default radius + l_rsnw = rsnw_fall if (present(rsnwn)) l_rsnw = rsnwn allocate(l_smice(nslyr,ncat)) @@ -2512,6 +2497,26 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_smliq = c0 if (present(smliqn)) l_smliq = smliqn + !----------------------------------------------------------------- + ! Initialize rate of snow loss to leads + !----------------------------------------------------------------- + + l_fsloss = fsnow * (c1 - aice) + + !----------------------------------------------------------------- + ! snow redistribution using snwlvlfac: precip factor + !----------------------------------------------------------------- + + if (trim(snwredist) == 'bulk') then + worka = c0 + do n = 1, ncat + worka = worka + alvl(n) + enddo + worka = worka * snwlvlfac/(c1+snwlvlfac) + l_fsloss = l_fsloss + fsnow*(c1-worka) + fsnow = fsnow* worka + endif ! snwredist + !----------------------------------------------------------------- ! Adjust frzmlt to account for ice-ocean heat fluxes since last ! call to coupler. @@ -2740,7 +2745,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & endif endif ! aicen_init - if (use_smliq_pnd) then + if (snwgrain .and. use_smliq_pnd) then call drain_snow (dt = dt, nslyr = nslyr, & vsnon = vsnon(n), aicen = aicen(n), & smice = l_smice(:,n), smliq = l_smliq(:,n), & @@ -2808,7 +2813,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & ! collect liquid water in ponds ! assume salt still runs off rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n) - if (use_smliq_pnd) then + if (snwgrain .and. use_smliq_pnd) then pond = rfrac/rhofresh * (melttn(n)*rhoi & + l_meltsliq(n)) else @@ -2889,6 +2894,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & enddo ! ncat + if (present(fsloss )) fsloss = l_fsloss if (present(isosno )) isosno = l_isosno if (present(isoice )) isoice = l_isoice if (present(Qa_iso )) Qa_iso = l_Qa_iso diff --git a/configuration/driver/icedrv_diagnostics.F90 b/configuration/driver/icedrv_diagnostics.F90 index 7472a94b0..50afbde62 100644 --- a/configuration/driver/icedrv_diagnostics.F90 +++ b/configuration/driver/icedrv_diagnostics.F90 @@ -9,7 +9,7 @@ module icedrv_diagnostics use icedrv_kinds use icedrv_constants, only: nu_diag, nu_diag_out use icedrv_domain_size, only: nx - use icedrv_domain_size, only: ncat, nfsd, n_iso + use icedrv_domain_size, only: ncat, nfsd, n_iso, nilyr, nslyr use icepack_intfc, only: c0 use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted use icepack_intfc, only: icepack_query_parameters @@ -66,7 +66,7 @@ subroutine runtime_diags (dt) use icedrv_flux, only: Tair, Qa, fsw, fcondtop use icedrv_flux, only: meltt, meltb, meltl, snoice use icedrv_flux, only: dsnow, congel, sst, sss, Tf, fhocn - use icedrv_state, only: aice, vice, vsno, trcr, trcrn, aicen + use icedrv_state, only: aice, vice, vsno, trcr, trcrn, aicen, vsnon real (kind=dbl_kind), intent(in) :: & dt ! time step @@ -77,13 +77,17 @@ subroutine runtime_diags (dt) n, nc, k logical (kind=log_kind) :: & - calc_Tsfc, tr_fsd, tr_iso + calc_Tsfc, snwgrain + + character (len=char_len) :: & + snwredist ! fields at diagnostic points real (kind=dbl_kind) :: & pTair, pfsnow, pfrain, & paice, hiavg, hsavg, hbravg, psalt, pTsfc, & - pevap, pfhocn, fsdavg + pevap, pfhocn, fsdavg, & + rsnwavg, rhosavg, smicetot, smliqtot, smtot real (kind=dbl_kind), dimension (nx) :: & work1, work2, work3 @@ -91,8 +95,9 @@ subroutine runtime_diags (dt) real (kind=dbl_kind) :: & Tffresh, rhos, rhow, rhoi - logical (kind=log_kind) :: tr_brine + logical (kind=log_kind) :: tr_brine, tr_fsd, tr_iso, tr_snow integer (kind=int_kind) :: nt_fbri, nt_Tsfc, nt_fsd, nt_isosno, nt_isoice + integer (kind=int_kind) :: nt_rsnw, nt_rhos, nt_smice, nt_smliq character(len=*), parameter :: subname='(runtime_diags)' @@ -100,11 +105,14 @@ subroutine runtime_diags (dt) ! query Icepack values !----------------------------------------------------------------- - call icepack_query_parameters(calc_Tsfc_out=calc_Tsfc) + call icepack_query_parameters(calc_Tsfc_out=calc_Tsfc, & + snwredist_out=snwredist, snwgrain_out=snwgrain) call icepack_query_tracer_flags(tr_brine_out=tr_brine, & - tr_fsd_out=tr_fsd,tr_iso_out=tr_iso) + tr_fsd_out=tr_fsd,tr_iso_out=tr_iso,tr_snow_out=tr_snow) call icepack_query_tracer_indices(nt_fbri_out=nt_fbri, nt_Tsfc_out=nt_Tsfc,& - nt_fsd_out=nt_fsd, nt_isosno_out=nt_isosno, nt_isoice_out=nt_isoice) + nt_fsd_out=nt_fsd, nt_isosno_out=nt_isosno, nt_isoice_out=nt_isoice, & + nt_rsnw_out=nt_rsnw, nt_rhos_out=nt_rhos, & + nt_smice_out=nt_smice, nt_smliq_out=nt_smliq) call icepack_query_parameters(Tffresh_out=Tffresh, rhos_out=rhos, & rhow_out=rhow, rhoi_out=rhoi) call icepack_warnings_flush(nu_diag) @@ -124,16 +132,21 @@ subroutine runtime_diags (dt) pfrain = frain(n)*dt/rhow ! rainfall paice = aice(n) ! ice area - hiavg = c0 ! avg snow/ice thickness + hiavg = c0 ! avg ice thickness + hsavg = c0 ! avg snow thickness fsdavg = c0 ! FSD rep radius - hsavg = c0 hbravg = c0 ! avg brine thickness + rsnwavg = c0 ! avg snow grain radius + rhosavg = c0 ! avg snow density + smicetot = c0 ! total mass of ice in snow (kg/m2) + smliqtot = c0 ! total mass of liquid in snow (kg/m2) + smtot = c0 ! total mass of snow volume (kg/m2) psalt = c0 if (paice /= c0) then - hiavg = vice(n)/paice - hsavg = vsno(n)/paice - if (tr_brine) hbravg = trcr(n,nt_fbri)* hiavg - if (tr_fsd) then + hiavg = vice(n)/paice + hsavg = vsno(n)/paice + if (tr_brine) hbravg = trcr(n,nt_fbri) * hiavg + if (tr_fsd) then ! avg floe size distribution do nc = 1, ncat do k = 1, nfsd fsdavg = fsdavg & @@ -141,7 +154,24 @@ subroutine runtime_diags (dt) * aicen(n,nc) / paice end do end do - end if + end if + if (tr_snow) then ! snow tracer quantities + do nc = 1, ncat + if (vsnon(n,nc) > c0) then + do k = 1, nslyr + rsnwavg = rsnwavg + trcrn(n,nt_rsnw +k-1,nc) ! snow grain radius + rhosavg = rhosavg + trcrn(n,nt_rhos +k-1,nc) ! compacted snow density + smicetot = smicetot + trcrn(n,nt_smice+k-1,nc) * vsnon(n,nc) + smliqtot = smliqtot + trcrn(n,nt_smliq+k-1,nc) * vsnon(n,nc) + end do + endif + smtot = smtot + rhos * vsnon(n,nc) ! mass of ice in standard density snow + end do + rsnwavg = rsnwavg / real(nslyr*ncat,kind=dbl_kind) ! snow grain radius + rhosavg = rhosavg / real(nslyr*ncat,kind=dbl_kind) ! compacted snow density + smicetot = smicetot / real(nslyr,kind=dbl_kind) ! mass of ice in snow + smliqtot = smliqtot / real(nslyr,kind=dbl_kind) ! mass of liquid in snow + end if endif if (vice(n) /= c0) psalt = work2(n)/vice(n) @@ -188,7 +218,6 @@ subroutine runtime_diags (dt) write(nu_diag_out+n-1,900) 'avg brine thickness (m)= ',hbravg if (tr_fsd) & write(nu_diag_out+n-1,900) 'avg fsd rep radius (m) = ',fsdavg - if (calc_Tsfc) then write(nu_diag_out+n-1,900) 'surface temperature(C) = ',pTsfc ! ice/snow @@ -208,6 +237,21 @@ subroutine runtime_diags (dt) write(nu_diag_out+n-1,900) 'effective dhi (m) = ',pdhi(n) ! ice thickness change write(nu_diag_out+n-1,900) 'effective dhs (m) = ',pdhs(n) ! snow thickness change write(nu_diag_out+n-1,900) 'intnl enrgy chng(W/m^2)= ',pde (n) ! ice/snow energy change + + if (tr_snow) then + if (trim(snwredist) /= 'none') then + write(nu_diag_out+n-1,900) 'avg snow density(kg/m3)= ',rhosavg + endif + if (snwgrain) then + write(nu_diag_out+n-1,900) 'avg snow grain radius = ',rsnwavg + write(nu_diag_out+n-1,900) 'mass ice in snow(kg/m2)= ',smicetot + write(nu_diag_out+n-1,900) 'mass liq in snow(kg/m2)= ',smliqtot + write(nu_diag_out+n-1,900) 'mass ice+liq (kg/m2)= ',smicetot+smliqtot + write(nu_diag_out+n-1,900) 'mass std snow (kg/m2)= ',smtot + write(nu_diag_out+n-1,900) 'max ice+liq (kg/m2)= ',rhow * hsavg + endif + endif + write(nu_diag_out+n-1,*) '----------ocn----------' write(nu_diag_out+n-1,900) 'sst (C) = ',sst(n) ! sea surface temperature write(nu_diag_out+n-1,900) 'sss (ppt) = ',sss(n) ! sea surface salinity @@ -270,7 +314,6 @@ end subroutine init_mass_diags subroutine total_energy (work) - use icedrv_domain_size, only: ncat, nilyr, nslyr use icedrv_state, only: vicen, vsnon, trcrn real (kind=dbl_kind), dimension (nx), intent(out) :: & @@ -331,7 +374,6 @@ end subroutine total_energy subroutine total_salt (work) - use icedrv_domain_size, only: ncat, nilyr use icedrv_state, only: vicen, trcrn real (kind=dbl_kind), dimension (nx), & @@ -397,7 +439,7 @@ subroutine icedrv_diagnostics_debug (plabeld) ! printing info for routine print_state integer (kind=int_kind), parameter :: & - check_step = 1439, & ! begin printing at istep1=check_step + check_step = 1, & ! begin printing at istep1=check_step ip = 3 ! i index if (istep1 >= check_step) then @@ -418,7 +460,6 @@ end subroutine icedrv_diagnostics_debug subroutine print_state(plabel,i) use icedrv_calendar, only: istep1, time - use icedrv_domain_size, only: nilyr, nslyr use icedrv_state, only: aice0, aicen, vicen, vsnon, uvel, vvel, trcrn use icedrv_flux, only: uatm, vatm, potT, Tair, Qa, flw, frain, fsnow use icedrv_flux, only: fsens, flat, evap, flwout @@ -444,8 +485,9 @@ subroutine print_state(plabel,i) integer (kind=int_kind) :: n, k integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno, nt_fsd + integer (kind=int_kind) :: nt_smice, nt_smliq - logical (kind=log_kind) :: tr_fsd + logical (kind=log_kind) :: tr_fsd, tr_snow character(len=*), parameter :: subname='(print_state)' @@ -453,9 +495,10 @@ subroutine print_state(plabel,i) ! query Icepack values !----------------------------------------------------------------- - call icepack_query_tracer_flags(tr_fsd_out=tr_fsd) + call icepack_query_tracer_flags(tr_fsd_out=tr_fsd, tr_snow_out=tr_snow) call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, & - nt_qsno_out=nt_qsno,nt_fsd_out=nt_fsd) + nt_qsno_out=nt_qsno,nt_fsd_out=nt_fsd, nt_smice_out=nt_smice, & + nt_smliq_out=nt_smliq) call icepack_query_parameters(puny_out=puny, Lfresh_out=Lfresh, cp_ice_out=cp_ice, & rhoi_out=rhoi, rhos_out=rhos) call icepack_warnings_flush(nu_diag) @@ -482,7 +525,9 @@ subroutine print_state(plabel,i) write(nu_diag,*) 'hsn', vsnon(i,n)/aicen(i,n) endif write(nu_diag,*) 'Tsfcn',trcrn(i,nt_Tsfc,n) - if (tr_fsd) write(nu_diag,*) 'afsdn',trcrn(i,nt_fsd,n) ! fsd cat 1 + if (tr_fsd ) write(nu_diag,*) 'afsdn',trcrn(i,nt_fsd,n) ! fsd cat 1 + if (tr_snow) write(nu_diag,*) 'smice',trcrn(i,nt_smice:nt_smice+nslyr-1,n) + if (tr_snow) write(nu_diag,*) 'smliq',trcrn(i,nt_smliq:nt_smliq+nslyr-1,n) write(nu_diag,*) ' ' enddo ! n diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 0e024142e..85b7b985f 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -426,14 +426,19 @@ subroutine input_data write (nu_diag,*) 'WARNING: snwredist on but tr_snow=F' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif - if (snwredist(1:9) == '30percent' .and. .not. tr_lvl) then - write (nu_diag,*) 'WARNING: snwredist=30percent but tr_lvl=F' + if (snwredist(1:4) == 'bulk' .and. .not. tr_lvl) then + write (nu_diag,*) 'WARNING: snwredist=bulk but tr_lvl=F' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif if (snwredist(1:6) == 'ITDrdg' .and. .not. tr_lvl) then write (nu_diag,*) 'WARNING: snwredist=ITDrdg but tr_lvl=F' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif + if (use_smliq_pnd .and. .not. snwgrain) then + write (nu_diag,*) 'WARNING: use_smliq_pnd = T but' + write (nu_diag,*) 'WARNING: snow metamorphosis not used' + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif if (use_smliq_pnd .and. .not. tr_snow) then write (nu_diag,*) 'WARNING: use_smliq_pnd = T but' write (nu_diag,*) 'WARNING: snow tracers are not active' @@ -1197,7 +1202,6 @@ subroutine set_state_var (nx, & use icedrv_domain_size, only: nilyr, nslyr, max_ntrcr, ncat, nfsd use icedrv_arrays_column, only: floe_rad_c, floe_binwidth - integer (kind=int_kind), intent(in) :: & nx ! number of grid cells @@ -1235,7 +1239,7 @@ subroutine set_state_var (nx, & real (kind=dbl_kind) :: & Tsfc, sum, hbar, & - rhos, Lfresh, puny + rhos, Lfresh, puny, rsnw_fall real (kind=dbl_kind), dimension(ncat) :: & ainit, hinit ! initial area, thickness @@ -1249,9 +1253,10 @@ subroutine set_state_var (nx, & real (kind=dbl_kind), parameter :: & hsno_init = 0.25_dbl_kind ! initial snow thickness (m) - logical (kind=log_kind) :: tr_brine, tr_lvl, tr_fsd + logical (kind=log_kind) :: tr_brine, tr_lvl, tr_fsd, tr_snow integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno, nt_sice, nt_fsd integer (kind=int_kind) :: nt_fbri, nt_alvl, nt_vlvl + integer (kind=int_kind) :: nt_rhos, nt_rsnw, nt_smice, nt_smliq character(len=*), parameter :: subname='(set_state_var)' @@ -1260,11 +1265,14 @@ subroutine set_state_var (nx, & !----------------------------------------------------------------- call icepack_query_tracer_flags(tr_brine_out=tr_brine, tr_lvl_out=tr_lvl, & - tr_fsd_out=tr_fsd) - call icepack_query_tracer_indices( nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, & + tr_fsd_out=tr_fsd, tr_snow_out=tr_snow) + call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, & nt_qsno_out=nt_qsno, nt_sice_out=nt_sice, nt_fsd_out=nt_fsd, & - nt_fbri_out=nt_fbri, nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl) - call icepack_query_parameters(rhos_out=rhos, Lfresh_out=Lfresh, puny_out=puny) + nt_fbri_out=nt_fbri, nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl, & + nt_rsnw_out=nt_rsnw, nt_rhos_out=nt_rhos, & + nt_smice_out=nt_smice, nt_smliq_out=nt_smliq) + call icepack_query_parameters(rhos_out=rhos, Lfresh_out=Lfresh, puny_out=puny, & + rsnw_fall_out=rsnw_fall) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) @@ -1352,6 +1360,15 @@ subroutine set_state_var (nx, & enddo ! nslyr ! brine fraction if (tr_brine) trcrn(i,nt_fbri,n) = c1 + ! snow radius, effective density, ice and liquid mass content + if (tr_snow) then + do k = 1, nslyr + trcrn(i,nt_rsnw +k-1,n) = rsnw_fall + trcrn(i,nt_rhos +k-1,n) = rhos + trcrn(i,nt_smice+k-1,n) = rhos + trcrn(i,nt_smliq+k-1,n) = c0 + enddo ! nslyr + endif enddo ! ncat call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -1413,11 +1430,20 @@ subroutine set_state_var (nx, & enddo ! nslyr ! brine fraction if (tr_brine) trcrn(i,nt_fbri,n) = c1 + ! snow radius, effective density, ice and liquid mass content + if (tr_snow) then + do k = 1, nslyr + trcrn(i,nt_rsnw +k-1,n) = rsnw_fall + trcrn(i,nt_rhos +k-1,n) = rhos + trcrn(i,nt_smice+k-1,n) = rhos + trcrn(i,nt_smliq+k-1,n) = c0 + enddo ! nslyr + endif enddo ! ncat call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__, line=__LINE__) - + !----------------------------------------------------------------- ! land diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index ebadbe1af..71100f53c 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -116,7 +116,7 @@ subroutine step_therm1 (dt) use icedrv_flux, only: meltsn, melttn, meltbn, congeln, snoicen, uatm, vatm use icedrv_flux, only: wind, rhoa, potT, Qa, Qa_iso, zlvl, strax, stray, flatn use icedrv_flux, only: fsensn, fsurfn, fcondtopn, fcondbotn - use icedrv_flux, only: flw, fsnow, fpond, sss, mlt_onset, frz_onset + use icedrv_flux, only: flw, fsnow, fpond, sss, mlt_onset, frz_onset, fsloss use icedrv_flux, only: frain, Tair, strairxT, strairyT, fsurf use icedrv_flux, only: fcondtop, fcondbot, fsens, fresh, fsalt, fhocn use icedrv_flux, only: flat, fswabs, flwout, evap, evaps, evapi @@ -312,7 +312,7 @@ subroutine step_therm1 (dt) Tbot = Tbot(i), Tsnice = Tsnice(i), & rside = rside(i), fside = fside(i), & fsnow = fsnow(i), frain = frain(i), & - fpond = fpond(i), & + fpond = fpond(i), fsloss = fsloss(i), & fsurf = fsurf(i), fsurfn = fsurfn(i,:), & fcondtop = fcondtop(i), fcondtopn = fcondtopn(i,:), & fcondbot = fcondbot(i), fcondbotn = fcondbotn(i,:), & diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 6679f9e52..3ef59032d 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -80,9 +80,9 @@ / &snow_nml - snwredist = 'none' - snwgrain = .false. - use_smliq_pnd = .false. + snwredist = 'ITDrdg' + snwgrain = .true. + use_smliq_pnd = .true. rsnw_fall = 54.526 rsnw_tmax = 1500.0 rhosnew = 100.0 From cc5fd0ffa9fc7de631e9c881e4332adc52a464f9 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 18 Mar 2021 17:51:58 -0600 Subject: [PATCH 17/47] make dsnow optional --- columnphysics/icepack_therm_vertical.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 886b74d20..72b0fe25e 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2219,7 +2219,6 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & meltt , & ! top ice melt (m/step-->cm/day) melts , & ! snow melt (m/step-->cm/day) meltb , & ! basal ice melt (m/step-->cm/day) - dsnow , & ! change in snow depth (m/step-->cm/day) mlt_onset , & ! day of year that sfc melting begins frz_onset ! day of year that freezing begins (congel or frazil) @@ -2228,6 +2227,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fswthru_vdf , & ! vis dif shortwave penetrating to ocean (W/m^2) fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) fswthru_idf , & ! nir dif shortwave penetrating to ocean (W/m^2) + dsnow , & ! change in snow depth (m/step-->cm/day) fsloss ! fraction of snow lost to leads real (kind=dbl_kind), dimension(:), optional, intent(inout) :: & From 36e5a650a113d755ec9f1ad1816d8fcb9530ba29 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Tue, 13 Apr 2021 18:38:12 -0600 Subject: [PATCH 18/47] snow aging table for dry metamorphism --- columnphysics/icepack_intfc.F90 | 2 + columnphysics/icepack_parameters.F90 | 30 +++--- columnphysics/icepack_snow.F90 | 132 +++++++++++++++++++----- configuration/driver/icedrv_InitMod.F90 | 4 + configuration/driver/icedrv_init.F90 | 17 ++- configuration/scripts/icepack_in | 1 + 6 files changed, 146 insertions(+), 40 deletions(-) diff --git a/columnphysics/icepack_intfc.F90 b/columnphysics/icepack_intfc.F90 index 07aac5084..ac4766d44 100644 --- a/columnphysics/icepack_intfc.F90 +++ b/columnphysics/icepack_intfc.F90 @@ -116,6 +116,8 @@ module icepack_intfc use icepack_mushy_physics , only: icepack_mushy_liquid_fraction use icepack_mushy_physics , only: icepack_mushy_temperature_mush + use icepack_snow, only: icepack_init_snow + use icepack_warnings, only: icepack_warnings_clear use icepack_warnings, only: icepack_warnings_print use icepack_warnings, only: icepack_warnings_flush diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index c9f0d5d2d..166f4104c 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -316,7 +316,8 @@ module icepack_parameters !----------------------------------------------------------------------- character (len=char_len), public :: & - snwredist = 'none' ! type of snow redistribution + snwredist = 'none', & ! type of snow redistribution + snw_aging_table = 'test' ! lookup table: 'snicar' or 'test' logical (kind=log_kind), public :: & use_smliq_pnd = .false. , & ! use liquid in snow for ponds @@ -332,16 +333,14 @@ module icepack_parameters drhosdwind = 27.3_dbl_kind, & ! wind compaction factor for snow (kg s/m^4) snwlvlfac = 0.3_dbl_kind ! fractional increase in snow ! depth for bulk redistribution - - ! indices for aging lookup table [idx] + ! indices for aging lookup table integer (kind=int_kind), public :: & - isnw_T = 11 , & ! maxiumum temperature index - isnw_Tgrd = 31 , & ! maxiumum temperature gradient index - isnw_rhos = 8 ! maxiumum snow density index + isnw_T, & ! maximum temperature index + isnw_Tgrd, & ! maximum temperature gradient index + isnw_rhos ! maximum snow density index ! dry snow aging parameters -! real (kind=dbl_kind), dimension(isnw_T,isnw_Tgrd,isnw_rhos), public :: & - real (kind=dbl_kind), dimension(11,31,8), public :: & + real (kind=dbl_kind), dimension(:,:,:), allocatable, public :: & snowage_tau, & ! (10^-6 m) snowage_kappa, & ! snowage_drdt0 ! (10^-6 m/hr) @@ -455,7 +454,8 @@ subroutine icepack_init_parameters( & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & rhosnew_in, rhosmin_in, rhosmax_in, windmin_in, drhosdwind_in, & snwlvlfac_in, isnw_T_in, isnw_Tgrd_in, isnw_rhos_in, & - snowage_tau_in, snowage_kappa_in, snowage_drdt0_in) + snowage_tau_in, snowage_kappa_in, snowage_drdt0_in, & + snw_aging_table_in) !----------------------------------------------------------------- ! parameter constants @@ -756,7 +756,8 @@ subroutine icepack_init_parameters( & !----------------------------------------------------------------------- character (len=char_len), intent(in), optional :: & - snwredist_in ! type of snow redistribution + snwredist_in, & ! type of snow redistribution + snw_aging_table_in ! snow aging lookup table logical (kind=log_kind), intent(in), optional :: & use_smliq_pnd_in, &! use liquid in snow for ponds @@ -896,6 +897,7 @@ subroutine icepack_init_parameters( & if (present(hs1_in) ) hs1 = hs1_in if (present(hp1_in) ) hp1 = hp1_in if (present(snwredist_in) ) snwredist = snwredist_in + if (present(snw_aging_table_in) ) snw_aging_table = snw_aging_table_in if (present(snwgrain_in) ) snwgrain = snwgrain_in if (present(use_smliq_pnd_in) ) use_smliq_pnd = use_smliq_pnd_in if (present(rsnw_fall_in) ) rsnw_fall = rsnw_fall_in @@ -1007,7 +1009,8 @@ subroutine icepack_query_parameters( & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & rhosnew_out, rhosmin_out, rhosmax_out, windmin_out, drhosdwind_out, & snwlvlfac_out, isnw_T_out, isnw_Tgrd_out, isnw_rhos_out, & - snowage_tau_out, snowage_kappa_out, snowage_drdt0_out) + snowage_tau_out, snowage_kappa_out, snowage_drdt0_out, & + snw_aging_table_out) !----------------------------------------------------------------- ! parameter constants @@ -1317,7 +1320,8 @@ subroutine icepack_query_parameters( & !----------------------------------------------------------------------- character (len=char_len), intent(out), optional :: & - snwredist_out ! type of snow redistribution + snwredist_out, & ! type of snow redistribution + snw_aging_table_out ! snow aging lookup table logical (kind=log_kind), intent(out), optional :: & use_smliq_pnd_out, &! use liquid in snow for ponds @@ -1497,6 +1501,7 @@ subroutine icepack_query_parameters( & if (present(hs1_out) ) hs1_out = hs1 if (present(hp1_out) ) hp1_out = hp1 if (present(snwredist_out) ) snwredist_out = snwredist + if (present(snw_aging_table_out) ) snw_aging_table_out = snw_aging_table if (present(snwgrain_out) ) snwgrain_out = snwgrain if (present(use_smliq_pnd_out) ) use_smliq_pnd_out= use_smliq_pnd if (present(rsnw_fall_out) ) rsnw_fall_out = rsnw_fall @@ -1694,6 +1699,7 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " hs1 = ", hs1 write(iounit,*) " hp1 = ", hp1 write(iounit,*) " snwredist = ", snwredist + write(iounit,*) " snw_aging_table = ", snw_aging_table write(iounit,*) " snwgrain = ", snwgrain write(iounit,*) " use_smliq_pnd = ", use_smliq_pnd write(iounit,*) " rsnw_fall = ", rsnw_fall diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index 6d16c4184..a714d4fa3 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -15,22 +15,103 @@ module icepack_snow use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind use icepack_parameters, only: isnw_T, isnw_Tgrd, isnw_rhos use icepack_parameters, only: snowage_tau, snowage_kappa, snowage_drdt0 + use icepack_parameters, only: snw_aging_table use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort implicit none private - public :: icepack_step_snow, drain_snow + public :: icepack_step_snow, drain_snow, icepack_init_snow real (kind=dbl_kind), parameter, public :: & S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) S_wet= 4.22e-5_dbl_kind ! (um^3/s) wet metamorphism parameters + ! shift in indices for aging test table + integer (kind=int_kind) :: & + iT_shift, & ! shift in maximum temperature index + iTgrd_shift, & ! shift in maximum temperature gradient index + irhos_shift ! shift in maximum snow density index + !======================================================================= contains +!======================================================================= +!autodocument_start icepack_init_snow +! Updates snow tracers +! +! authors: Elizabeth C. Hunke, LANL +! Nicole Jeffery, LANL + + subroutine icepack_init_snow + +!autodocument_end + + ! local variables + + character (len=*),parameter :: subname='(icepack_init_snow)' + + !----------------------------------------------------------------- + ! Snow metamorphism lookup table + !----------------------------------------------------------------- + + if (snwgrain) then + if (trim(snw_aging_table) == 'snicar') then ! read netcdf file + isnw_T = 11 ! maxiumum temperature index + isnw_Tgrd = 31 ! maxiumum temperature gradient index + isnw_rhos = 8 ! maxiumum snow density index + allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) + allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T)) + allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T)) + iT_shift = 0 ! use entire table + iTgrd_shift = 0 ! + irhos_shift = 0 ! + elseif (trim(snw_aging_table) == 'test') then + isnw_T = 5 ! maxiumum temperature index + isnw_Tgrd = 5 ! maxiumum temperature gradient index + isnw_rhos = 1 ! maxiumum snow density index + allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) + allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T)) + allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T)) + iT_shift = 4 ! index adjustments for subset of table + iTgrd_shift = 0 ! + irhos_shift = 5 ! + + ! Subset of dry snow aging parameters + snowage_tau = reshape((/ & + 3.34947394_dbl_kind, 4.02124159_dbl_kind, 4.03328223_dbl_kind, & + 3.02686921_dbl_kind, 2.14125851_dbl_kind, 3.97008737_dbl_kind, & + 4.72725821_dbl_kind, 3.65313459_dbl_kind, 2.41198936_dbl_kind, & + 2.53065623e-1_dbl_kind, 4.60286630_dbl_kind, 4.99721440_dbl_kind, & + 3.29168191_dbl_kind, 2.66426779e-1_dbl_kind, 9.15830596e-5_dbl_kind, & + 5.33186128_dbl_kind, 4.90833452_dbl_kind, 1.55269141_dbl_kind, & + 1.31225526e-3_dbl_kind, 9.36078196e-4_dbl_kind, 6.25428631_dbl_kind, & + 5.04394794_dbl_kind, 2.92857366e-3_dbl_kind, 9.01488751e-3_dbl_kind, & + 1.19037046e-2_dbl_kind/), & + (/isnw_rhos,isnw_Tgrd,isnw_T/)) + + snowage_kappa = reshape((/ & + 0.60824438, 0.56442972, 0.5527807, 0.64299537, 0.77672359, & + 0.57105932, 0.52791041, 0.59868076, 0.7487191, 1.57946877, & + 0.54236508, 0.52458285, 0.65520877, 1.52356017, 4.37789838, & + 0.51449138, 0.54494334, 0.91628508, 3.28847035, 3.64418487, & + 0.48538708, 0.55386601, 2.81247103, 2.72445522, 2.8230216/), & + (/isnw_rhos,isnw_Tgrd,isnw_T/)) + + snowage_drdt0 = reshape((/ & + 1.26597871, 1.26602416, 1.26613263, 1.26620414, 1.26629424, & + 1.92418877, 1.92430063, 1.92445964, 1.92451557, 1.92469806, & + 2.79086547, 2.79147315, 2.79137562, 2.79150846, 2.79216439, & + 3.85605846, 3.85668001, 3.85844559, 3.86073682, 3.863199, & + 5.0861907, 5.08765668, 5.09200195, 5.09665276, 5.10079895/), & + (/isnw_rhos,isnw_Tgrd,isnw_T/)) + endif + endif + + end subroutine icepack_init_snow + !======================================================================= !autodocument_start icepack_step_snow ! Updates snow tracers @@ -756,11 +837,10 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & !----------------------------------------------------------------- ! dry metamorphism !----------------------------------------------------------------- -!echmod - data for table can not be read by Icepack -! call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & -! drsnw_dry, zqsn(:,n), Tsfc(n), & -! zTin(n), hsn(n), hin(n), & -! smice(:,n), smliq(:,n)) + call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & + drsnw_dry, zqsn(:,n), Tsfc(n), & + zTin(n), hsn(n), hin(n), & + smice(:,n), smliq(:,n)) !----------------------------------------------------------------- ! wet metamorphism @@ -771,14 +851,14 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k)) enddo - else + else ! hsn or hin < puny do k = 1,nslyr ! rsnw_fall < rsnw < rsnw_tmax rsnw (k,n) = max(rsnw_fall, min(rsnw_tmax, rsnw(k,n))) smice(k,n) = rhos smliq(k,n) = c0 enddo - endif + endif ! hsn, hin enddo end subroutine update_snow_radius @@ -866,7 +946,6 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & zTsn(1) = (Lfresh + zqsn(1)/rhos)/cp_ice if (nslyr == 1) then - zdTdz(1) = min(c10*isnw_Tgrd, & !ech refactored abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny)) abs(zTsn(1)*dzi + zTin1*dzs - Tsfc*dz)/(dz*hsn+puny)) @@ -882,26 +961,33 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & enddo !ech refactored zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) & !ech refactored - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny) - zdTdz(nslyr) = p5*abs((zTin1-zTsn(nslyr))/(dz+puny) - zTsn(nslyr-1)/(dzs+puny)) + zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs) & + - (zTsn(nslyr) + zTsn(nslyr-1))*p5*dz) / (dz*dzs+puny) zdTdz(nslyr) = min(c10*isnw_Tgrd, zdTdz(nslyr)) endif -!echmod - table will not be available in Icepack standalone (netcdf) - - ! best-fit parameters are read from a table - ! 11 temperatures from 225 to 273 K - ! 31 temperature gradients from 0 to 300 K/m - ! 8 snow densities from 0 to 350 kg/m3 - ! pointer snowage_tau, snowage_kappa, snowage_drdt0 - - do k = 1, nslyr + ! if snw_aging_table = 'snicar' + ! best-fit parameters are read from a table (netcdf) + ! snowage_tau, snowage_kappa, snowage_drdt0 + ! 11 temperatures from 225 to 273 K + ! 31 temperature gradients from 0 to 300 K/m + ! 8 snow densities from 0 to 350 kg/m3 + + ! if snw_aging_table = 'test' + ! for testing Icepack without netcdf, + ! use a subsampled, hard-coded table + ! 5 temperatures + ! 5 temperature gradients + ! 1 snow density + + do k = 1, nslyr zrhos(k) = smice(k) + smliq(k) ! best-fit table indices: - T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind) - Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind) - !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! variable density - rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) ! fixed density + T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind) - iT_shift + Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind) - iTgrd_shift + !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) - irhos_shift ! variable density + rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) - irhos_shift ! fixed density ! boundary check: T_idx = min(isnw_T, max(1,T_idx+1)) diff --git a/configuration/driver/icedrv_InitMod.F90 b/configuration/driver/icedrv_InitMod.F90 index e3e33b0dd..52d2a7f66 100644 --- a/configuration/driver/icedrv_InitMod.F90 +++ b/configuration/driver/icedrv_InitMod.F90 @@ -37,6 +37,7 @@ subroutine icedrv_initialize init_calendar, calendar use icepack_intfc, only: icepack_init_itd, icepack_init_itd_hist use icepack_intfc, only: icepack_init_fsd_bounds + use icepack_intfc, only: icepack_init_snow use icepack_intfc, only: icepack_warnings_flush use icedrv_domain_size, only: ncat, nfsd ! use icedrv_diagnostics, only: icedrv_diagnostics_debug @@ -52,6 +53,7 @@ subroutine icedrv_initialize logical (kind=log_kind) :: & skl_bgc, & ! from icepack z_tracers, & ! from icepack + tr_snow, & ! from icepack tr_aero, & ! from icepack tr_iso, & ! from icepack tr_zaero, & ! from icepack @@ -128,6 +130,7 @@ subroutine icedrv_initialize call icepack_query_parameters(skl_bgc_out=skl_bgc) call icepack_query_parameters(z_tracers_out=z_tracers) call icepack_query_parameters(wave_spec_out=wave_spec) + call icepack_query_tracer_flags(tr_snow_out=tr_snow) call icepack_query_tracer_flags(tr_aero_out=tr_aero) call icepack_query_tracer_flags(tr_iso_out=tr_iso) call icepack_query_tracer_flags(tr_zaero_out=tr_zaero) @@ -140,6 +143,7 @@ subroutine icedrv_initialize if (tr_fsd .and. wave_spec) call get_wave_spec ! wave spectrum in ice call get_forcing(istep1) ! get forcing from data arrays + if (tr_snow) call icepack_init_snow ! snow aging table if (tr_iso) call fiso_default ! default values ! aerosols ! if (tr_aero) call faero_data ! data file diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 85b7b985f..657cf1022 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -96,10 +96,10 @@ subroutine input_data natmiter, kitd, kcatbound character (len=char_len) :: shortwave, albedo_type, conduct, fbot_xfer_type, & - tfrz_option, frzpnd, atmbndy, wave_spec_type, snwredist + tfrz_option, frzpnd, atmbndy, wave_spec_type, snwredist, snw_aging_table logical (kind=log_kind) :: sw_redist, use_smliq_pnd, snwgrain - real (kind=dbl_kind) :: sw_frac, sw_dtemp + real (kind=dbl_kind) :: sw_frac, sw_dtemp ! Flux convergence tolerance real (kind=dbl_kind) :: atmiter_conv @@ -155,11 +155,10 @@ subroutine input_data hs0, dpscale, frzpnd, & rfracmin, rfracmax, pndaspect, hs1, & hp1 - namelist /snow_nml/ & snwredist, snwgrain, rsnw_fall, rsnw_tmax, & rhosnew, rhosmin, rhosmax, snwlvlfac, & - windmin, drhosdwind, use_smliq_pnd + windmin, drhosdwind, use_smliq_pnd, snw_aging_table namelist /forcing_nml/ & atmbndy, calc_strair, calc_Tsfc, & @@ -223,7 +222,8 @@ subroutine input_data snwredist_out=snwredist, use_smliq_pnd_out=use_smliq_pnd, & snwgrain_out=snwgrain, rsnw_fall_out=rsnw_fall, rsnw_tmax_out=rsnw_tmax, & rhosnew_out=rhosnew, rhosmin_out = rhosmin, rhosmax_out=rhosmax, & - windmin_out=windmin, drhosdwind_out=drhosdwind, snwlvlfac_out=snwlvlfac) + windmin_out=windmin, drhosdwind_out=drhosdwind, snwlvlfac_out=snwlvlfac, & + snw_aging_table_out=snw_aging_table) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -448,6 +448,11 @@ subroutine input_data write (nu_diag,*) 'WARNING: snwgrain=T but tr_snow=F' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif + if (trim(snw_aging_table) /= 'test') then + write (nu_diag,*) 'WARNING: snw_aging_table /= test' + write (nu_diag,*) 'WARNING: netcdf not available' + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif if (tr_iso .and. n_iso==0) then write (nu_diag,*) 'WARNING: isotopes activated but' @@ -614,6 +619,7 @@ subroutine input_data write(nu_diag,1030) ' snwredist = ', snwredist write(nu_diag,1010) ' snwgrain = ', snwgrain write(nu_diag,1010) ' use_smliq_pnd = ', use_smliq_pnd + write(nu_diag,1030) ' snw_aging_table = ', snw_aging_table write(nu_diag,1000) ' rsnw_fall = ', rsnw_fall write(nu_diag,1000) ' rsnw_tmax = ', rsnw_tmax write(nu_diag,1000) ' rhosnew = ', rhosnew @@ -861,6 +867,7 @@ subroutine input_data wave_spec_type_in=wave_spec_type, wave_spec_in=wave_spec, & sw_redist_in=sw_redist, sw_frac_in=sw_frac, sw_dtemp_in=sw_dtemp, & snwredist_in=snwredist, use_smliq_pnd_in=use_smliq_pnd, & + snw_aging_table_in=snw_aging_table, & snwgrain_in=snwgrain, rsnw_fall_in=rsnw_fall, rsnw_tmax_in=rsnw_tmax, & rhosnew_in=rhosnew, rhosmin_in=rhosmin, rhosmax_in=rhosmax, & windmin_in=windmin, drhosdwind_in=drhosdwind, snwlvlfac_in=snwlvlfac) diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 3ef59032d..2f566d41b 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -91,6 +91,7 @@ windmin = 10.0 drhosdwind = 27.3 snwlvlfac = 0.3 + snw_aging_table = 'test' / &forcing_nml From 91d3930fdb976a2db161a28a18b8000471a513ec Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Wed, 14 Apr 2021 08:17:59 -0600 Subject: [PATCH 19/47] env for snwgrain test --- configuration/scripts/options/set_env.snwgrain | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 configuration/scripts/options/set_env.snwgrain diff --git a/configuration/scripts/options/set_env.snwgrain b/configuration/scripts/options/set_env.snwgrain new file mode 100644 index 000000000..9540293c6 --- /dev/null +++ b/configuration/scripts/options/set_env.snwgrain @@ -0,0 +1,2 @@ +setenv NSNWLYR 3 # number of vertical layers in the snow + From a2fda56c93bdbd643e3c8f6d37fd994c2bfca3dc Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 15 Apr 2021 15:14:33 -0600 Subject: [PATCH 20/47] snow documentation, first draft --- configuration/driver/icedrv_diagnostics.F90 | 2 +- doc/source/master_list.bib | 38 ++++++ doc/source/science_guide/index.rst | 1 + doc/source/science_guide/sg_snow.rst | 128 ++++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100755 doc/source/science_guide/sg_snow.rst diff --git a/configuration/driver/icedrv_diagnostics.F90 b/configuration/driver/icedrv_diagnostics.F90 index 50afbde62..d5f6f60ea 100644 --- a/configuration/driver/icedrv_diagnostics.F90 +++ b/configuration/driver/icedrv_diagnostics.F90 @@ -165,7 +165,7 @@ subroutine runtime_diags (dt) smliqtot = smliqtot + trcrn(n,nt_smliq+k-1,nc) * vsnon(n,nc) end do endif - smtot = smtot + rhos * vsnon(n,nc) ! mass of ice in standard density snow + smtot = smtot + rhos * vsnon(n,nc) ! mass of ice in standard density snow end do rsnwavg = rsnwavg / real(nslyr*ncat,kind=dbl_kind) ! snow grain radius rhosavg = rhosavg / real(nslyr*ncat,kind=dbl_kind) ! compacted snow density diff --git a/doc/source/master_list.bib b/doc/source/master_list.bib index 1a1e1b73e..c8170d086 100644 --- a/doc/source/master_list.bib +++ b/doc/source/master_list.bib @@ -742,6 +742,44 @@ @article{danabasoglu20 year = {2020} } +@Article{Sturm02, + author = "M. Sturm and J. Holmgren and D. K. Perovich", + title = "{Winter snow cover on the sea ice of the Arctic Ocean at the Surface Heat Budget of the Arctic Ocean (SHEBA): Temporal evolution and spatial variability}", + journal = JGRO, + year = {2002}, + volume = {107}, + issue = {C10}, + url = {https://doi.org/10.1029/2000JC000400} +} + +@Article{Lecomte13, + author = "O. Lecomte and T. Fichefet and M. Vancoppenolle and F. Domine and F. Massonet and P. Mathiot and S. Morin and P. Y. Barriat", + title = "{On the formulation of snow thermal conductivity in large-scale sea ice models}", + journal = JAMES, + year = {2013}, + volume = {5}, + issue = {3}, + pages = {542-557}, + url = {https://doi.org/10.1002/jame.20039} +} + +@Article{Lecomte15, + author = "O. Lecomte and T. Fichefet and D. Flocco and D. Schroeder and M. Vancoppenolle", + title = "{Interactions between wind-blown snow redistribution and melt ponds in a coupled ocean-sea ice model}", + journal = OM, + year = {2015}, + volume = {87}, + pages = {67-80}, + url = {https://doi.org/10.1016/j.ocemod.2014.12.003} +} + +@Manual{Oleson10, + author = "W. K. Oleson and D. M. Lawrence and G. B. Bonan and M. G. Flanner and E. Kluzek and P. J. Lawrence and S. Levis and S. C. Swenson and P. E. Thornton", + title = "{Technical description of version 4.0 of the Community Land Model (CLM)}", + organization = "NCAR Technical Note NCAR/TN-478+STR, National Center for Atmospheric Research", + year = {2019}, + url = {https://opensky.ucar.edu/islandora/object/technotes:493} +} % ********************************************** diff --git a/doc/source/science_guide/index.rst b/doc/source/science_guide/index.rst index 0ef243883..eafffde1f 100755 --- a/doc/source/science_guide/index.rst +++ b/doc/source/science_guide/index.rst @@ -17,5 +17,6 @@ Science Guide sg_transport.rst sg_mechanical.rst sg_thermo.rst + sg_snow.rst sg_bgc.rst diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst new file mode 100755 index 000000000..2946bb5c5 --- /dev/null +++ b/doc/source/science_guide/sg_snow.rst @@ -0,0 +1,128 @@ +:tocdepth: 3 + +.. _snow: + +Advanced Snow Physics +===================== + +Once deposited, the character and distribution of snow on sea ice depend on re-transport (wind), melting/wetting, and metamorphism (chiefly producing low-conductivity depth hoar or snow-ice). Each of these processes affects the other, and they are crucial for the evolution of the sea ice pack :cite:`Sturm02`. In particular, Wind slab and depth hoar resist densification, and Wind slab may prevent snow from drifting after deposition. Snow drifts around ridges cover only 6% of the ice surface area and are about 30% deeper than other snow-covered areas, but they prevent seawater filled cracks around the ridges from freezing, with important biological consequences. + +The standard model configuration includes a basic snow formulation describing the essential effects of snow on sea ice, such as its albedo, vertical conduction, and growth/melt processes. It also incorporates more detailed processes such as snow-ice formation due to flooding and snow infiltration by melt water, which may form melt ponds. Several potentially important processes are not included in the standard configuration, such as compaction and redistribution of snow by wind and their effects on the thermal balance and on effective roughness. Snow metamorphism due to temperature gradients and liquid water content also are not included. + +Setting ``tr_snow = .true.`` activates advanced snow physics parameterizations that represent the following processes: + +1. Radiative effect of snow redistribution by wind with respect to ice topography, including snow compaction by wind + +2. Radiative effects of snow grain metamorphism (variable grain size) + +3. Coupling effects of including fresh water and heat associated with snow saturation + +Snow can be scoured from level ice, blowing into leads and ponds, or piling up on ridges. + +The presence of liquid water in snow, such as rain or melt water, changes the surface albedo dramatically. It also alters the conductivity of the snow pack. These effects are associated mainly with the formation of depth hoar (change in grain size). + +Except for the topo melt pond scheme, melt water and heat in ponds (which may be hidden within a partially saturated snow pack) are ``virtual" in the sense that they are provided to the ocean model component immediately upon melting, even though the effects of the liquid water continue to be tracked as if it were retained on the ice. Retaining that water and heat in the sea ice component alters the timing, location and magnitude of fresh water runoff events into the ocean. + +The standard model configuration assumes that the snow depth is uniform across each ice thickness category within a grid cell for the vertical thermodynamic calculation. However, there are separate radiation calculations for bare ice, snow-covered ice, and pond-covered ice; snow and ponds interact through snow saturation levels. Redistributing the snow alters these radiative calculations. + +Because the thermodynamic schemes in CICE assume a uniform snow depth over each category, ignoring the fractions of level and deformed ice, effects of snow redistribution are included only via the delta-Eddington radiation scheme. The redistributed snow depth is used to determine the effective area of bare ice (for very small snow depths) and the effective area and depth of melt ponds over level ice. Once those areas are determined, the redistributed snow volume over them is known, from which the snow depth for the remaining snow-covered area can be computed and used for its radiation balance calculation. + +Two basic approaches are available for snow redistribution by wind, ``snwredist = bulk``, for which a user-defined parameter :math:`p` (``snwlvlfac``) determines the ratio of snow on ridges to that on level ice, and ``snwITDrdg``, in which snow can be compacted by the wind or eroded and redeposited on other thickness categories. For both, nonlocal redistribution of snow (i.e., between grid cells) is neglected, assuming that the difference between snow mass blowing into a grid cell and that blowing out is negligible, but snow can be blown into nearby leads and open water. + +.. _snow_bulk: + +Bulk snow redistribution +------------------------ + +:cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m−2 s−1, which accumulates snow only on the ice-covered area of the grid cell. + +There are two levels of sophistication at which this approach can be accomplished: (1) assuming the snow removed from the level ice area is deposited into leads, and (2) assuming the snow removed from the level ice area is deposited onto ridges. Case (1) affects both the radiative and thermodynamic calculations by reducing the total amount of snow on the ice. Case (2) affects the radiative calculation directly, by possibly exposing more bare ice or melt ponds, but it affects the thermodynamic (conduction) calculation only through the altered radiative absorption, since the snow is always assumed to be equally deep over both level and deformed ice for the thermodynamic calculation. + +ECH CHECK WHAT IS DONE IN THE CODE + +When ``snwredist = bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: + +.. math:: + f_s^\prime = f_s a_{lvl} \left({1\over{1+p}}}\right), + +where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the level-ice tracer value, and primed quantities represent their modified values. + +Snow is redistributed between level and ridged ice within a single thickness category by solving a pair of equations for the modified level- and ridged-ice snow depths in terms of the original snow depth: + +.. math:: + h_{lvl}^\prime = {1\over {1+p(1-a_{lvl})}} h_{lvl} + +.. math:: + h_{rdg}^\prime = {{1 + p}\over {1+p(1-a_{lvl})}} h_{lvl}. + + In the shortwave module for level-ice ponds, we create a new variable :math:`h_{lvl}^\prime`, ``hsnlvl``) for snow depth over the level ice, and replace ``hsn`` with ``hsnlvl`` for the snow infiltration calculation and for the calculation of snow depth over refrozen melt ponds. + +.. _snow_windredist: + +Snow redistribution by wind +--------------------------- + +Following :cite:`Lecomte15`, we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`Phi` for snow mass as the sum of an erosion rate :math:`Phi_E` and a redeposition rate :math:`Phi_R` for each category of thickness :math:`h_i`: + +.. math:: + Phi_E = {\partial m \over \partial t}_{erosion} = -{\gamma \over \sigma_{ITD}} \left(V-V^*\right){\rho_{max} - \rho_s \over \rho_{max}} + +where :math:`\rho_s` and :math:\rho_{max}` are the effective snow density and the maximum snow density in the model, respectively. For now, we take :math:`\rho_s` to be the wind-compacted snow density computed at the end of the snow model time step. + +:math:`Phi_E \Delta t` represents the maximum snow mass per unit area that may be suspended from each category, subject to the total mass (per unit area) available on each category. +Erosion begins when the instantaneous wind speed :math:`V` exceeds the seasonal wind speed required to compact the snow to a density :math:`\rhos`, :math:`V^* = (\rho_s − \beta)/\alpha`. :math:`\sigma_{ITD}` is the standard deviation of the ice thicknesses from the thickness distribution :math:`g` within the grid cell. :math:`\gamma` is a tuning coefficient for +the eroded mass, which :cite:`Lecomte15` set to :math:`10^{-5}` kg m:math:`^{-2}`. From :cite:`Lecomte13`, :math:`\rho_s = 44.6V^* + 174` kg m:math:`^{−3}` for seasonal mean wind speed :math:`V` ,i.e. :math:`\alpha=174` kg m:math:`^{-3}` and :math:`\beta=44.6` kg s m:math:`^{-4}`. + +In :cite:`Lecomte15`, the fraction of this suspended snow lost in leads is + +.. math:: + f = \left(1-a_i\right) \exp(\sigma_{ITD}\over\sigma_{ref}), + +where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. That is, the snow mass that is redistribution on the ice (i.e., not lost in leads) is + +.. math:: + Phi_R \Delta t = a_i \left(1-f\right) \Phi_E \Delta t. + +We extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, + +.. math:: + \sigma_{ITD}^2 = \sum_{n=1]^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1]^N a_{ik}h_{ik}\right)^2 + a_{in}a_{rdgn} \left(h_{irdgn - \sum_{k=1]^N a_{ik}h_{ik}\right)^2. + +When considering snow over ridged and level ice for the redistribution, we reapportion the fraction of snow on level ice as :math:`a_slvl = 1-(1+p)a_{rdg}` and note that with + +.. math:: + a_{slvl} = {\sum_{n=1]^N a_{in}\left(a_{lvln} - p a_{rdgn}\right) \over \sum_{n=1}^N a_{in}} + +a conservative redistribution of snow across thickness categories is (for each category :math:`n`) + +.. math:: + Phi_R(n) \Delta t = a_i \left(1-f\right) \left[a_{rdgn}\left(1+p\right) + a_{slvl} \right] \Phi_E \Delta t, + +where :math:`p \le a_{lvln}/a_{rdgn}`. + +The snow volume and energy state variables are updated in two steps, first for erosion of snow into suspension, then snow redeposition. When redepositing the snow, the snow energy is distributed among the snow layers affected by erosion, proportionally to the fraction of snow eroded. Finally, snow layer thicknesses are re-equalized, conserving snow energy. The fraction of suspended snow mass and energy lost in leads is added to the fresh water and heat fluxes for strict conservation. + +.. _snow_windcompact: + +Snow compaction by wind +----------------------- + +High wind speeds compact the upper portion of a snow pack into ``wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. + +:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. ``Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m:math:`^{−3}` and ``soft slab" is :math:`\rho_s` = 321 kg m:math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. +For simplicity, we assign a minimum snow density of :math:`\rho_s^{min} = 100 kg m:math:`^{−3}` s +and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right). +This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following the [6] suggestion, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. + +.. _snow_metamorphosis: + +Metamorphosis of snow grains +---------------------------- + +:cite:`Oleson10` + + + Dynamic effective snow grain radius (snow pack has memory). Adds 3 snow tracers +– Temperature gradient metamorphism (depth hoar formation, same as land model snow) +– Snow ages (grain size increases) with liquid content from rain and melt + From 17d39422087b3dfe11a1d78ec28551851967a37b Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 15 Apr 2021 15:51:54 -0600 Subject: [PATCH 21/47] snow case settings --- doc/source/user_guide/ug_case_settings.rst | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 76b54d9d1..588e016a7 100755 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -184,6 +184,7 @@ tracer_nml "``tr_pond_cesm``", "logical", "CESM melt ponds", "``.false.``" "``tr_pond_lvl``", "logical", "level-ice melt ponds", "``.false.``" "``tr_pond_topo``", "logical", "topo melt ponds", "``.false.``" + "``tr_snow``", "logical", "advanced snow physics", "``.false.``" "", "", "", "" thermo_nml @@ -278,6 +279,31 @@ ponds_nml "``rfracmin``", ":math:`0 \le r_{min} \le 1`", "minimum melt water added to ponds", "0.15" "", "", "", "" +snow_nml +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: **snow_nml namelist options** + :header: "variable", "options/format", "description", "default value" + :widths: 15, 15, 30, 15 + + "", "", "", "" + "``drhosdwind``", "real", "wind compaction factor for snow", "27.3" + "``rhosmin``", "real", "minimum snow density", "100.0" + "``rhosmax``", "real", "minimum snow density", "450.0" + "``rhosnew``", "real", "new snow density", "100.0" + "``rsnw_fall``", "real", "radius of new snow (um)", "54.526" + "``rsnw_tmax``", "real", "max snow radius (um)", "1500.0" + "``snw_aging_table``", "test", "snow aging lookup table", "test" + "", "snicar", "(not available in Icepack)", "" + "``snwgrain``", "logical", "snow grain metamorphosis", ".true." + "``snwlvlfac``", "real", "fraction bulk snow depth incr.", "0.3" + "``snwredist``", "``snwITDrdg``", "snow redistribution, ITD/ridges", "snwITDrdg" + "", "``bulk``", "bulk snow redistribution", "" + "", "``none``", "no snow redistribution", "" + "``use_smliq_pnd``", "logical", "use liquid in snow for ponds", ".true." + "``windmin``", "real", "min wind speed to compact snow", "10.0" + "", "", "", "" + forcing_nml ~~~~~~~~~~~~~~~~~~~~~~~~~ From 014e0fcbe6b9d65cbf01b30d47c5f62c640e801a Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 15 Apr 2021 18:04:44 -0600 Subject: [PATCH 22/47] fix step_therm1 interface and some documentation errors --- configuration/driver/icedrv_step.F90 | 38 ++++++++++++++++++-------- doc/source/science_guide/sg_snow.rst | 41 ++++++++++++++-------------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 71100f53c..57b9f235c 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -154,7 +154,7 @@ subroutine step_therm1 (dt) logical (kind=log_kind) :: & tr_iage, tr_FY, tr_aero, tr_iso, tr_pond, tr_pond_cesm, & - tr_pond_lvl, tr_pond_topo, calc_Tsfc + tr_pond_lvl, tr_pond_topo, calc_Tsfc, tr_snow real (kind=dbl_kind), dimension(n_aero,2,ncat) :: & aerosno, aeroice ! kg/m^2 @@ -162,6 +162,9 @@ subroutine step_therm1 (dt) real (kind=dbl_kind), dimension(n_iso,ncat) :: & isosno, isoice ! kg/m^2 + real (kind=dbl_kind), dimension(nslyr,ncat) :: & + rsnwn, smicen, smliqn + real (kind=dbl_kind) :: & puny @@ -185,7 +188,7 @@ subroutine step_therm1 (dt) call icepack_query_tracer_flags( & tr_iage_out=tr_iage, tr_FY_out=tr_FY, & - tr_aero_out=tr_aero, tr_iso_out=tr_iso, & + tr_aero_out=tr_aero, tr_iso_out=tr_iso, tr_snow_out=tr_snow, & tr_pond_out=tr_pond, tr_pond_cesm_out=tr_pond_cesm, & tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo) call icepack_warnings_flush(nu_diag) @@ -211,6 +214,9 @@ subroutine step_therm1 (dt) aeroice(:,:,:) = c0 isosno (:,:) = c0 isoice (:,:) = c0 + rsnwn (:,:) = c0 + smicen (:,:) = c0 + smliqn (:,:) = c0 do i = 1, nx @@ -234,8 +240,8 @@ subroutine step_therm1 (dt) !echmod do i = 3,3 if (tr_aero) then ! trcrn(nt_aero) has units kg/m^3 - do n=1,ncat - do k=1,n_aero + do n = 1, ncat + do k = 1, n_aero aerosno (k,:,n) = & trcrn(i,nt_aero+(k-1)*4 :nt_aero+(k-1)*4+1,n) & * vsnon_init(i,n) @@ -248,14 +254,24 @@ subroutine step_therm1 (dt) if (tr_iso) then ! trcrn(nt_isosno/ice) has units kg/m^3 - do n=1,ncat - do k=1,n_iso + do n = 1, ncat + do k = 1, n_iso isosno(k,n) = trcrn(i,nt_isosno+k-1,n) * vsnon_init(i,n) isoice(k,n) = trcrn(i,nt_isoice+k-1,n) * vicen_init(i,n) enddo enddo endif ! tr_iso -!print*,' driver i', i + + if (tr_snow) then + do n = 1, ncat + do k = 1, nslyr + rsnwn (k,n) = trcrn(i,nt_rsnw +k-1,n) + smicen(k,n) = trcrn(i,nt_smice+k-1,n) + smliqn(k,n) = trcrn(i,nt_smliq+k-1,n) + enddo + enddo + endif ! tr_snow + call icepack_step_therm1(dt=dt, ncat=ncat, nilyr=nilyr, nslyr=nslyr, & aicen_init = aicen_init(i,:), & vicen_init = vicen_init(i,:), & @@ -275,9 +291,9 @@ subroutine step_therm1 (dt) ipnd = trcrn(i,nt_ipnd,:), & iage = trcrn(i,nt_iage,:), & FY = trcrn(i,nt_FY,:), & - rsnwn = trcrn(i,nt_rsnw :nt_rsnw +nslyr-1,:), & - smicen = trcrn(i,nt_smice:nt_smice+nslyr-1,:), & - smliqn = trcrn(i,nt_smliq:nt_smliq+nslyr-1,:), & + rsnwn = rsnwn (:,:), & + smicen = smicen(:,:), & + smliqn = smliqn(:,:), & aerosno = aerosno(:,:,:), & aeroice = aeroice(:,:,:), & isosno = isosno(:,:), & @@ -353,7 +369,7 @@ subroutine step_therm1 (dt) congel = congel(i), congeln = congeln(i,:), & snoice = snoice(i), snoicen = snoicen(i,:), & dsnow = dsnow(i), dsnown = dsnown(i,:), & - meltsliqn=meltsliqn(i,:), & + meltsliqn= meltsliqn(i,:), & lmask_n = lmask_n(i), lmask_s = lmask_s(i), & mlt_onset=mlt_onset(i), frz_onset = frz_onset(i), & yday = yday, prescribed_ice = prescribed_ice) diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 2946bb5c5..1cbfa5300 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -2,14 +2,14 @@ .. _snow: -Advanced Snow Physics +Advanced snow physics ===================== Once deposited, the character and distribution of snow on sea ice depend on re-transport (wind), melting/wetting, and metamorphism (chiefly producing low-conductivity depth hoar or snow-ice). Each of these processes affects the other, and they are crucial for the evolution of the sea ice pack :cite:`Sturm02`. In particular, Wind slab and depth hoar resist densification, and Wind slab may prevent snow from drifting after deposition. Snow drifts around ridges cover only 6% of the ice surface area and are about 30% deeper than other snow-covered areas, but they prevent seawater filled cracks around the ridges from freezing, with important biological consequences. The standard model configuration includes a basic snow formulation describing the essential effects of snow on sea ice, such as its albedo, vertical conduction, and growth/melt processes. It also incorporates more detailed processes such as snow-ice formation due to flooding and snow infiltration by melt water, which may form melt ponds. Several potentially important processes are not included in the standard configuration, such as compaction and redistribution of snow by wind and their effects on the thermal balance and on effective roughness. Snow metamorphism due to temperature gradients and liquid water content also are not included. -Setting ``tr_snow = .true.`` activates advanced snow physics parameterizations that represent the following processes: +Setting ``tr_snow`` = ``.true.`` activates advanced snow physics parameterizations that represent the following processes: 1. Radiative effect of snow redistribution by wind with respect to ice topography, including snow compaction by wind @@ -21,29 +21,29 @@ Snow can be scoured from level ice, blowing into leads and ponds, or piling up o The presence of liquid water in snow, such as rain or melt water, changes the surface albedo dramatically. It also alters the conductivity of the snow pack. These effects are associated mainly with the formation of depth hoar (change in grain size). -Except for the topo melt pond scheme, melt water and heat in ponds (which may be hidden within a partially saturated snow pack) are ``virtual" in the sense that they are provided to the ocean model component immediately upon melting, even though the effects of the liquid water continue to be tracked as if it were retained on the ice. Retaining that water and heat in the sea ice component alters the timing, location and magnitude of fresh water runoff events into the ocean. +Except for the topo melt pond scheme, melt water and heat in ponds (which may be hidden within a partially saturated snow pack) are "virtual" in the sense that they are provided to the ocean model component immediately upon melting, even though the effects of the liquid water continue to be tracked as if it were retained on the ice. Retaining that water and heat in the sea ice component alters the timing, location and magnitude of fresh water runoff events into the ocean. The standard model configuration assumes that the snow depth is uniform across each ice thickness category within a grid cell for the vertical thermodynamic calculation. However, there are separate radiation calculations for bare ice, snow-covered ice, and pond-covered ice; snow and ponds interact through snow saturation levels. Redistributing the snow alters these radiative calculations. Because the thermodynamic schemes in CICE assume a uniform snow depth over each category, ignoring the fractions of level and deformed ice, effects of snow redistribution are included only via the delta-Eddington radiation scheme. The redistributed snow depth is used to determine the effective area of bare ice (for very small snow depths) and the effective area and depth of melt ponds over level ice. Once those areas are determined, the redistributed snow volume over them is known, from which the snow depth for the remaining snow-covered area can be computed and used for its radiation balance calculation. -Two basic approaches are available for snow redistribution by wind, ``snwredist = bulk``, for which a user-defined parameter :math:`p` (``snwlvlfac``) determines the ratio of snow on ridges to that on level ice, and ``snwITDrdg``, in which snow can be compacted by the wind or eroded and redeposited on other thickness categories. For both, nonlocal redistribution of snow (i.e., between grid cells) is neglected, assuming that the difference between snow mass blowing into a grid cell and that blowing out is negligible, but snow can be blown into nearby leads and open water. +Two basic approaches are available for snow redistribution by wind, ``snwredist`` = ``bulk``, for which a user-defined parameter :math:`p` (``snwlvlfac``) determines the ratio of snow on ridges to that on level ice, and ``snwITDrdg``, in which snow can be compacted by the wind or eroded and redeposited on other thickness categories. For both, nonlocal redistribution of snow (i.e., between grid cells) is neglected, assuming that the difference between snow mass blowing into a grid cell and that blowing out is negligible, but snow can be blown into nearby leads and open water. .. _snow_bulk: Bulk snow redistribution ------------------------ -:cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m−2 s−1, which accumulates snow only on the ice-covered area of the grid cell. +:cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m :math:`^{−2}` s :math:`^{−1}`, which accumulates snow only on the ice-covered area of the grid cell. There are two levels of sophistication at which this approach can be accomplished: (1) assuming the snow removed from the level ice area is deposited into leads, and (2) assuming the snow removed from the level ice area is deposited onto ridges. Case (1) affects both the radiative and thermodynamic calculations by reducing the total amount of snow on the ice. Case (2) affects the radiative calculation directly, by possibly exposing more bare ice or melt ponds, but it affects the thermodynamic (conduction) calculation only through the altered radiative absorption, since the snow is always assumed to be equally deep over both level and deformed ice for the thermodynamic calculation. ECH CHECK WHAT IS DONE IN THE CODE -When ``snwredist = bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: +When ``snwredist`` = ``bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: .. math:: - f_s^\prime = f_s a_{lvl} \left({1\over{1+p}}}\right), + f_{s}^\prime = f_s a_{lvl} \left({1\over{1+p}}}\right), where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the level-ice tracer value, and primed quantities represent their modified values. @@ -55,7 +55,7 @@ Snow is redistributed between level and ridged ice within a single thickness cat .. math:: h_{rdg}^\prime = {{1 + p}\over {1+p(1-a_{lvl})}} h_{lvl}. - In the shortwave module for level-ice ponds, we create a new variable :math:`h_{lvl}^\prime`, ``hsnlvl``) for snow depth over the level ice, and replace ``hsn`` with ``hsnlvl`` for the snow infiltration calculation and for the calculation of snow depth over refrozen melt ponds. +In the shortwave module for level-ice ponds, we create a new variable :math:`h_{lvl}^\prime`, ``hsnlvl``) for snow depth over the level ice, and replace ``hsn`` with ``hsnlvl`` for the snow infiltration calculation and for the calculation of snow depth over refrozen melt ponds. .. _snow_windredist: @@ -65,38 +65,39 @@ Snow redistribution by wind Following :cite:`Lecomte15`, we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`Phi` for snow mass as the sum of an erosion rate :math:`Phi_E` and a redeposition rate :math:`Phi_R` for each category of thickness :math:`h_i`: .. math:: - Phi_E = {\partial m \over \partial t}_{erosion} = -{\gamma \over \sigma_{ITD}} \left(V-V^*\right){\rho_{max} - \rho_s \over \rho_{max}} + \Phi_E = \left({\partial m \over \partial t}\right)_{erosion} = -{\gamma \over \sigma_{ITD}} \left(V-V^*\right){\rho_{max} - \rho_s \over \rho_{max}} -where :math:`\rho_s` and :math:\rho_{max}` are the effective snow density and the maximum snow density in the model, respectively. For now, we take :math:`\rho_s` to be the wind-compacted snow density computed at the end of the snow model time step. +where :math:`\rho_s` and :math:`\rho_{max}` are the effective snow density and the maximum snow density in the model, respectively. For now, we take :math:`\rho_s` to be the wind-compacted snow density computed at the end of the snow model time step. :math:`Phi_E \Delta t` represents the maximum snow mass per unit area that may be suspended from each category, subject to the total mass (per unit area) available on each category. -Erosion begins when the instantaneous wind speed :math:`V` exceeds the seasonal wind speed required to compact the snow to a density :math:`\rhos`, :math:`V^* = (\rho_s − \beta)/\alpha`. :math:`\sigma_{ITD}` is the standard deviation of the ice thicknesses from the thickness distribution :math:`g` within the grid cell. :math:`\gamma` is a tuning coefficient for -the eroded mass, which :cite:`Lecomte15` set to :math:`10^{-5}` kg m:math:`^{-2}`. From :cite:`Lecomte13`, :math:`\rho_s = 44.6V^* + 174` kg m:math:`^{−3}` for seasonal mean wind speed :math:`V` ,i.e. :math:`\alpha=174` kg m:math:`^{-3}` and :math:`\beta=44.6` kg s m:math:`^{-4}`. + +Erosion begins when the instantaneous wind speed :math:`V` exceeds the seasonal wind speed required to compact the snow to a density :math:`\rho_s`, :math:`V^* = (\rho_s − \beta)/\alpha`. :math:`\sigma_{ITD}` is the standard deviation of the ice thicknesses from the thickness distribution :math:`g` within the grid cell. :math:`\gamma` is a tuning coefficient for +the eroded mass, which :cite:`Lecomte15` set to :math:`10^{-5}` kg m :math:`^{-2}`. From :cite:`Lecomte13`, :math:`\rho_s = 44.6V^* + 174` kg m :math:`^{−3}` for seasonal mean wind speed :math:`V` ,i.e. :math:`\alpha=174` kg m :math:`^{-3}` and :math:`\beta=44.6` kg s m :math:`^{-4}`. In :cite:`Lecomte15`, the fraction of this suspended snow lost in leads is .. math:: - f = \left(1-a_i\right) \exp(\sigma_{ITD}\over\sigma_{ref}), + f = \left(1-a_i\right) \exp({\sigma_{ITD}\over\sigma_{ref}}), where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. That is, the snow mass that is redistribution on the ice (i.e., not lost in leads) is .. math:: - Phi_R \Delta t = a_i \left(1-f\right) \Phi_E \Delta t. + \Phi_R \Delta t = a_i \left(1-f\right) \Phi_E \Delta t. We extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, .. math:: - \sigma_{ITD}^2 = \sum_{n=1]^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1]^N a_{ik}h_{ik}\right)^2 + a_{in}a_{rdgn} \left(h_{irdgn - \sum_{k=1]^N a_{ik}h_{ik}\right)^2. + \sigma_{ITD}^2 = \sum_{n=1}^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1}^N a_{ik}h_{ik}\right)^2 + a_{in}a_{rdgn} \left(h_{irdgn - \sum_{k=1}^N a_{ik}h_{ik}\right)^2. When considering snow over ridged and level ice for the redistribution, we reapportion the fraction of snow on level ice as :math:`a_slvl = 1-(1+p)a_{rdg}` and note that with .. math:: - a_{slvl} = {\sum_{n=1]^N a_{in}\left(a_{lvln} - p a_{rdgn}\right) \over \sum_{n=1}^N a_{in}} + a_{slvl} = {\sum_{n=1}^N a_{in}\left(a_{lvln} - p a_{rdgn}\right) \over \sum_{n=1}^N a_{in}} a conservative redistribution of snow across thickness categories is (for each category :math:`n`) .. math:: - Phi_R(n) \Delta t = a_i \left(1-f\right) \left[a_{rdgn}\left(1+p\right) + a_{slvl} \right] \Phi_E \Delta t, + \Phi_R(n) \Delta t = a_i \left(1-f\right) \left[a_{rdgn}\left(1+p\right) + a_{slvl} \right] \Phi_E \Delta t, where :math:`p \le a_{lvln}/a_{rdgn}`. @@ -109,9 +110,9 @@ Snow compaction by wind High wind speeds compact the upper portion of a snow pack into ``wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. -:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. ``Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m:math:`^{−3}` and ``soft slab" is :math:`\rho_s` = 321 kg m:math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. -For simplicity, we assign a minimum snow density of :math:`\rho_s^{min} = 100 kg m:math:`^{−3}` s -and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right). +:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{−3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. +For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{−3}` s +and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right)`. This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following the [6] suggestion, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. .. _snow_metamorphosis: From 1c7b6d0ae249bf46db6dd497e725830b27a5582f Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 15 Apr 2021 18:18:40 -0600 Subject: [PATCH 23/47] documentation corrections --- doc/source/science_guide/sg_snow.rst | 16 ++++++++-------- doc/source/user_guide/ug_case_settings.rst | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 1cbfa5300..cfa9ad778 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -43,7 +43,7 @@ ECH CHECK WHAT IS DONE IN THE CODE When ``snwredist`` = ``bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: .. math:: - f_{s}^\prime = f_s a_{lvl} \left({1\over{1+p}}}\right), + f_{s}^\prime = {f_s a_{lvl} \left({1\over{1+p}}\right)}, where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the level-ice tracer value, and primed quantities represent their modified values. @@ -62,22 +62,22 @@ In the shortwave module for level-ice ponds, we create a new variable :math:`h_{ Snow redistribution by wind --------------------------- -Following :cite:`Lecomte15`, we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`Phi` for snow mass as the sum of an erosion rate :math:`Phi_E` and a redeposition rate :math:`Phi_R` for each category of thickness :math:`h_i`: +Following :cite:`Lecomte15`, we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`\Phi` for snow mass as the sum of an erosion rate :math:`\Phi_E` and a redeposition rate :math:`\Phi_R` for each category of thickness :math:`h_i`: .. math:: \Phi_E = \left({\partial m \over \partial t}\right)_{erosion} = -{\gamma \over \sigma_{ITD}} \left(V-V^*\right){\rho_{max} - \rho_s \over \rho_{max}} where :math:`\rho_s` and :math:`\rho_{max}` are the effective snow density and the maximum snow density in the model, respectively. For now, we take :math:`\rho_s` to be the wind-compacted snow density computed at the end of the snow model time step. -:math:`Phi_E \Delta t` represents the maximum snow mass per unit area that may be suspended from each category, subject to the total mass (per unit area) available on each category. +:math:`\Phi_E \Delta t` represents the maximum snow mass per unit area that may be suspended from each category, subject to the total mass (per unit area) available on each category. Erosion begins when the instantaneous wind speed :math:`V` exceeds the seasonal wind speed required to compact the snow to a density :math:`\rho_s`, :math:`V^* = (\rho_s − \beta)/\alpha`. :math:`\sigma_{ITD}` is the standard deviation of the ice thicknesses from the thickness distribution :math:`g` within the grid cell. :math:`\gamma` is a tuning coefficient for -the eroded mass, which :cite:`Lecomte15` set to :math:`10^{-5}` kg m :math:`^{-2}`. From :cite:`Lecomte13`, :math:`\rho_s = 44.6V^* + 174` kg m :math:`^{−3}` for seasonal mean wind speed :math:`V` ,i.e. :math:`\alpha=174` kg m :math:`^{-3}` and :math:`\beta=44.6` kg s m :math:`^{-4}`. +the eroded mass, which :cite:`Lecomte15` set to :math:`10^{-5}` kg m :math:`^{-2}`. From :cite:`Lecomte13`, :math:`\rho_s = 44.6V^* + 174` kg m :math:`^{−3}` for seasonal mean wind speed :math:`V`, i.e. :math:`\alpha=174` kg m :math:`^{-3}` and :math:`\beta=44.6` kg s m :math:`^{-4}`. In :cite:`Lecomte15`, the fraction of this suspended snow lost in leads is .. math:: - f = \left(1-a_i\right) \exp({\sigma_{ITD}\over\sigma_{ref}}), + f = \left(1-a_i\right) \exp\left({\sigma_{ITD}\over\sigma_{ref}}\right), where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. That is, the snow mass that is redistribution on the ice (i.e., not lost in leads) is @@ -87,9 +87,9 @@ where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice We extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, .. math:: - \sigma_{ITD}^2 = \sum_{n=1}^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1}^N a_{ik}h_{ik}\right)^2 + a_{in}a_{rdgn} \left(h_{irdgn - \sum_{k=1}^N a_{ik}h_{ik}\right)^2. + \sigma_{ITD}^2 = \sum_{n=1}^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1}^N a_{ik}h_{ik}\right)^2 + a_{in} a_{rdgn} \left(h_{irdgn} - \sum_{k=1}^N a_{ik} h_{ik} \right)^2. -When considering snow over ridged and level ice for the redistribution, we reapportion the fraction of snow on level ice as :math:`a_slvl = 1-(1+p)a_{rdg}` and note that with +When considering snow over ridged and level ice for the redistribution, we reapportion the fraction of snow on level ice as :math:`a_{slvl} = 1-(1+p)a_{rdg}` and note that with the average expression .. math:: a_{slvl} = {\sum_{n=1}^N a_{in}\left(a_{lvln} - p a_{rdgn}\right) \over \sum_{n=1}^N a_{in}} @@ -108,7 +108,7 @@ The snow volume and energy state variables are updated in two steps, first for e Snow compaction by wind ----------------------- -High wind speeds compact the upper portion of a snow pack into ``wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. +High wind speeds compact the upper portion of a snow pack into "wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. :cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{−3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{−3}` s diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 588e016a7..09891acb1 100755 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -289,19 +289,19 @@ snow_nml "", "", "", "" "``drhosdwind``", "real", "wind compaction factor for snow", "27.3" "``rhosmin``", "real", "minimum snow density", "100.0" - "``rhosmax``", "real", "minimum snow density", "450.0" + "``rhosmax``", "real", "maximum snow density", "450.0" "``rhosnew``", "real", "new snow density", "100.0" "``rsnw_fall``", "real", "radius of new snow (um)", "54.526" - "``rsnw_tmax``", "real", "max snow radius (um)", "1500.0" + "``rsnw_tmax``", "real", "maximum snow radius (um)", "1500.0" "``snw_aging_table``", "test", "snow aging lookup table", "test" "", "snicar", "(not available in Icepack)", "" "``snwgrain``", "logical", "snow grain metamorphosis", ".true." - "``snwlvlfac``", "real", "fraction bulk snow depth incr.", "0.3" - "``snwredist``", "``snwITDrdg``", "snow redistribution, ITD/ridges", "snwITDrdg" + "``snwlvlfac``", "real", "fraction increase in bulk snow redistribution", "0.3" + "``snwredist``", "``snwITDrdg``", "snow redistribution using ITD/ridges", "snwITDrdg" "", "``bulk``", "bulk snow redistribution", "" "", "``none``", "no snow redistribution", "" "``use_smliq_pnd``", "logical", "use liquid in snow for ponds", ".true." - "``windmin``", "real", "min wind speed to compact snow", "10.0" + "``windmin``", "real", "minimum wind speed to compact snow", "10.0" "", "", "", "" forcing_nml From 177940c19447346a5e634360d69f3a06588903cb Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 16 Apr 2021 07:06:40 -0600 Subject: [PATCH 24/47] complete step_therm1 interface fix; bug fix in bgc diagnostics --- .../driver/icedrv_diagnostics_bgc.F90 | 26 ++++++++++++------- configuration/driver/icedrv_step.F90 | 10 +++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/configuration/driver/icedrv_diagnostics_bgc.F90 b/configuration/driver/icedrv_diagnostics_bgc.F90 index 151a72680..e593eb530 100644 --- a/configuration/driver/icedrv_diagnostics_bgc.F90 +++ b/configuration/driver/icedrv_diagnostics_bgc.F90 @@ -764,15 +764,17 @@ subroutine zsal_diags () ! vertical fields of category 1 at diagnostic points for bgc layer model real (kind=dbl_kind), dimension(nblyr+2) :: & pphin, pphin1 + real (kind=dbl_kind), dimension(nilyr) :: & + pSice real (kind=dbl_kind), dimension(nblyr) :: & - pSin, pSice, pSin1 + pSin, pSin1 real (kind=dbl_kind), dimension(nblyr+1) :: & pbTiz, piDin real (kind=dbl_kind) :: & rhosi, rhow, rhos - logical (kind=log_kind) :: tr_brine + logical (kind=log_kind) :: tr_brine, solve_zsal integer (kind=int_kind) :: nt_fbri, nt_bgc_S, nt_sice character(len=*), parameter :: subname='(zsal_diags)' @@ -781,7 +783,8 @@ subroutine zsal_diags () ! query Icepack values !----------------------------------------------------------------- - call icepack_query_parameters(rhosi_out=rhosi, rhow_out=rhow, rhos_out=rhos) + call icepack_query_parameters(rhosi_out=rhosi, rhow_out=rhow, rhos_out=rhos, & + solve_zsal_out=solve_zsal) call icepack_query_tracer_flags(tr_brine_out=tr_brine) call icepack_query_tracer_indices(nt_fbri_out=nt_fbri, & nt_bgc_S_out=nt_bgc_S, nt_sice_out=nt_sice) @@ -804,22 +807,24 @@ subroutine zsal_diags () pdh_top1 = c0 pdh_bot1 = c0 pdarcy_V1 = c0 + do nn = 1, ncat psice_rho = psice_rho(n) + sice_rho(n,nn)*aicen(n,nn) enddo if (aice(n) > c0) psice_rho = psice_rho/aice(n) - if (tr_brine .and. aice(n) > c0) & + + if (tr_brine .and. aice(n) > c0) then phinS = trcr(n,nt_fbri)*vice(n)/aice(n) - if (aicen(n,1) > c0) then - if (tr_brine) phinS1 = trcrn(n,nt_fbri,1) & - * vicen(n,1)/aicen(n,1) + phbrn = (c1 - rhosi/rhow)*vice(n)/aice(n) & + - rhos /rhow *vsno(n)/aice(n) + endif + if (tr_brine .and. aicen(n,1) > c0) then + phinS1 = trcrn(n,nt_fbri,1)*vicen(n,1)/aicen(n,1) pdh_top1 = dhbr_top(n,1) pdh_bot1 = dhbr_bot(n,1) pdarcy_V1 = darcy_V(n,1) endif - if (tr_brine .AND. aice(n) > c0) & - phbrn = (c1 - rhosi/rhow)*vice(n)/aice(n) & - - rhos /rhow *vsno(n)/aice(n) + do k = 1, nblyr+1 pbTiz(k) = c0 piDin(k) = c0 @@ -847,6 +852,7 @@ subroutine zsal_diags () pSin (k) = trcr(n,nt_bgc_S+k-1) if (aicen(n,1) > c0) pSin1(k) = trcrn(n,nt_bgc_S+k-1,1) enddo + do k = 1,nilyr pSice(k) = trcr(n,nt_sice+k-1) enddo diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 57b9f235c..dad6c3791 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -400,6 +400,16 @@ subroutine step_therm1 (dt) enddo endif ! tr_iso + if (tr_snow) then + do n = 1, ncat + do k = 1, nslyr + trcrn(i,nt_rsnw +k-1,n) = rsnwn (k,n) + trcrn(i,nt_smice+k-1,n) = smicen(k,n) + trcrn(i,nt_smliq+k-1,n) = smliqn(k,n) + enddo + enddo + endif ! tr_snow + enddo ! i call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & From 0faa997ee65cfeef9fea0bb1d0e75109a2fc08c6 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 16 Apr 2021 10:49:36 -0600 Subject: [PATCH 25/47] metamorphism updates to doc with notes for things needing to be checked against the code --- .../driver/icedrv_diagnostics_bgc.F90 | 2 +- doc/source/science_guide/sg_snow.rst | 45 ++++++++++++++++--- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/configuration/driver/icedrv_diagnostics_bgc.F90 b/configuration/driver/icedrv_diagnostics_bgc.F90 index e593eb530..fd84b9d88 100644 --- a/configuration/driver/icedrv_diagnostics_bgc.F90 +++ b/configuration/driver/icedrv_diagnostics_bgc.F90 @@ -774,7 +774,7 @@ subroutine zsal_diags () real (kind=dbl_kind) :: & rhosi, rhow, rhos - logical (kind=log_kind) :: tr_brine, solve_zsal + logical (kind=log_kind) :: tr_brine integer (kind=int_kind) :: nt_fbri, nt_bgc_S, nt_sice character(len=*), parameter :: subname='(zsal_diags)' diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index cfa9ad778..6031fd85a 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -29,6 +29,8 @@ Because the thermodynamic schemes in CICE assume a uniform snow depth over each Two basic approaches are available for snow redistribution by wind, ``snwredist`` = ``bulk``, for which a user-defined parameter :math:`p` (``snwlvlfac``) determines the ratio of snow on ridges to that on level ice, and ``snwITDrdg``, in which snow can be compacted by the wind or eroded and redeposited on other thickness categories. For both, nonlocal redistribution of snow (i.e., between grid cells) is neglected, assuming that the difference between snow mass blowing into a grid cell and that blowing out is negligible, but snow can be blown into nearby leads and open water. + + .. _snow_bulk: Bulk snow redistribution @@ -79,12 +81,24 @@ In :cite:`Lecomte15`, the fraction of this suspended snow lost in leads is .. math:: f = \left(1-a_i\right) \exp\left({\sigma_{ITD}\over\sigma_{ref}}\right), -where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. That is, the snow mass that is redistribution on the ice (i.e., not lost in leads) is +where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. + +DELETE? +We also allow blowing snow to be caught in melt ponds, + +.. math:: + f = \left(1 - a_i - a_p a_{lvl} a_i\right) \exp\left({\sigma_{ITD}\over\sigma_{ref}}\right). + +If the ponds are frozen, the snow blown into them will accumulate on top of the pond ice; otherwise the new snow will contribute to any existing snow within the pond area. +END DELETE? [also 'or ponds' in the next line] + + +Thus, the snow mass that is redistribution on the ice (i.e., not lost in leads[DELETE? or ponds]) is .. math:: \Phi_R \Delta t = a_i \left(1-f\right) \Phi_E \Delta t. -We extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, +We [DELETE? further] extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, .. math:: \sigma_{ITD}^2 = \sum_{n=1}^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1}^N a_{ik}h_{ik}\right)^2 + a_{in} a_{rdgn} \left(h_{irdgn} - \sum_{k=1}^N a_{ik} h_{ik} \right)^2. @@ -115,15 +129,34 @@ For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 k and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right)`. This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following the [6] suggestion, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. +.. _snow_liquid: + +Ice and liquid water mass in snow +--------------------------------- + +The advanced snow physics option calculates ice and liquid water mass and effective snow grain radius, enabling them to interact with the radiation calculation. The mass of ice and liquid water in snow are implemented as tracers on snow volume layers and used for the snow grain metamorphism. +Together with snow volume, they also can be used to determine effective snow density as :math:`\rho_s^{eff} = m_{ice}+m_{liq} / h_s`. Note that :math:`m_{ice}+m_{liq}` (kg/m :math:`^2`) is the snow water equivalent. + +Sources of :math:`m_{ice}` are snowfall, condensation, and freezing of liquid water within the snowpack; sinks are sublimation and melting. All of the sources and sinks of mice:math:`m_{ice}` are already computed in the code except for freezing of liquid water within the snow pack. + +Sources of :math:`m_{liq}` are rain and snow melt; freezing of liquid water within the snowpack and runoff are sinks. Runoff and meltwater entering a snow layer (i.e., runoff from the layer above) are associated with vertical flow through the snow column. As in :cite:`Oleson10`, when the liquid water within a snow layer exceeds the layer’s holding capacity, the excess water is added to the underlying layer, limited by the effective porosity of the layer. The flow of water is assumed to be zero if the effective porosity of either of the two layers is less than 0.05, the water-impermeable volumetric water content. [IS THIS TRUE? CHECK CONSERVATION] Excess water is supplied to the melt pond parameterization, which puts a fraction of it into the pond volume and allows the rest to run off into the ocean. + +The snow mass fractions of precipitation, [CHECK] refrozen ice and old ice are saved for metamorphosing the snow grain radius. + +[CHECK]Code users will be able to choose whether heat and fresh water associated with liquid water in snow (or ponds) is held according to physical processes in the model or immediately fluxed to the ocean. The model will conserve both heat and water in either case. + .. _snow_metamorphosis: Metamorphosis of snow grains ---------------------------- -:cite:`Oleson10` +Dynamic, effective snow radius, a snow volume tracer, evolves analytically as a function of snow temperature, temperature gradient, and density for radiative calculations using the delta-Eddington radiation scheme. +Wet metamorphism changes both density (through volume change) and effective grain size; here we only consider changes in grain radius. +In the formation of depth hoar, dry snow kinetic metamorphism (TG metamorphism) also increases the snow grain radius. + +The tracers :math:`m_{liq}` and :math:`m_{ice}` characterize the snow in each snow layer, for each ice category and horizontal grid cell. The model's meltpond volume covers a fraction of the grid cell and represents liquid in excess of :math:`m_{liq}`. The radiative effects of snow grain radius in the fraction of ice covered by pond volume are only calculated when the pond volume has not yet saturated the snow pack; otherwise, delta-Eddington transfer uses meltpond properties. Therefore, modelled changes in snow grain radii from metamorphism are designed specifically for the fraction without exposed (i.e. effective) melt ponds. + +Following :cite:`Oleson10`, the new snow grain radius is computed as a weighted function of existing, new (freshly fallen)[CHECK, and refrozen] snow grain radii, using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density. - Dynamic effective snow grain radius (snow pack has memory). Adds 3 snow tracers -– Temperature gradient metamorphism (depth hoar formation, same as land model snow) -– Snow ages (grain size increases) with liquid content from rain and melt From 61b79b59f6db3e5789d318e8b32251ab713d26d8 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 16 Apr 2021 10:51:55 -0600 Subject: [PATCH 26/47] remove unused variable --- configuration/driver/icedrv_diagnostics_bgc.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configuration/driver/icedrv_diagnostics_bgc.F90 b/configuration/driver/icedrv_diagnostics_bgc.F90 index fd84b9d88..55f2a6e04 100644 --- a/configuration/driver/icedrv_diagnostics_bgc.F90 +++ b/configuration/driver/icedrv_diagnostics_bgc.F90 @@ -783,8 +783,7 @@ subroutine zsal_diags () ! query Icepack values !----------------------------------------------------------------- - call icepack_query_parameters(rhosi_out=rhosi, rhow_out=rhow, rhos_out=rhos, & - solve_zsal_out=solve_zsal) + call icepack_query_parameters(rhosi_out=rhosi, rhow_out=rhow, rhos_out=rhos) call icepack_query_tracer_flags(tr_brine_out=tr_brine) call icepack_query_tracer_indices(nt_fbri_out=nt_fbri, & nt_bgc_S_out=nt_bgc_S, nt_sice_out=nt_sice) From 8366f5666ff6990c729cd19f5672f76c0f4cc102 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 16 Apr 2021 12:55:10 -0600 Subject: [PATCH 27/47] add snow tests to base_suite --- configuration/scripts/tests/base_suite.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configuration/scripts/tests/base_suite.ts b/configuration/scripts/tests/base_suite.ts index 194ffbf33..2e2bcc42d 100644 --- a/configuration/scripts/tests/base_suite.ts +++ b/configuration/scripts/tests/base_suite.ts @@ -16,6 +16,8 @@ smoke col 1x1 debug,run1year,leap,dt30min smoke col 1x1 debug,run1year,dyn smoke col 1x1 debug,run1year,fsd12 smoke col 1x1 debug,run1year,fsd1 +smoke col 1x1 debug,run1year,snwITDrdg,snwgrain +smoke col 1x1 debug,run1year,snw30percent restart col 1x1 debug restart col 1x1 diag1 restart col 1x1 pondcesm @@ -32,4 +34,5 @@ restart col 1x1 alt03 restart col 1x1 alt04 restart col 1x1 dyn restart col 1x1 fsd12 +restart col 1x1 snwITDrdg,snwgrain From 3c947c9e87dead1cd935a4d49376b6fc3d6984b3 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 6 May 2021 13:13:48 -0600 Subject: [PATCH 28/47] initialize snow tracer indices when unused; update documentation --- configuration/driver/icedrv_init.F90 | 4 ++++ doc/source/science_guide/sg_snow.rst | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 657cf1022..676bf08c0 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -750,6 +750,10 @@ subroutine input_data endif endif + nt_smice = max_ntrcr + nt_smliq = max_ntrcr + nt_rhos = max_ntrcr + nt_rsnw = max_ntrcr if (tr_snow) then nt_smice = ntrcr + 1 ntrcr = ntrcr + nslyr ! mass of ice in nslyr snow layers diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 6031fd85a..fac1e3f76 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -127,7 +127,7 @@ High wind speeds compact the upper portion of a snow pack into "wind slab," a de :cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{−3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{−3}` s and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right)`. -This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following the [6] suggestion, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. +This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following :cite:`Sturm02`, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. .. _snow_liquid: @@ -139,9 +139,9 @@ Together with snow volume, they also can be used to determine effective snow den Sources of :math:`m_{ice}` are snowfall, condensation, and freezing of liquid water within the snowpack; sinks are sublimation and melting. All of the sources and sinks of mice:math:`m_{ice}` are already computed in the code except for freezing of liquid water within the snow pack. -Sources of :math:`m_{liq}` are rain and snow melt; freezing of liquid water within the snowpack and runoff are sinks. Runoff and meltwater entering a snow layer (i.e., runoff from the layer above) are associated with vertical flow through the snow column. As in :cite:`Oleson10`, when the liquid water within a snow layer exceeds the layer’s holding capacity, the excess water is added to the underlying layer, limited by the effective porosity of the layer. The flow of water is assumed to be zero if the effective porosity of either of the two layers is less than 0.05, the water-impermeable volumetric water content. [IS THIS TRUE? CHECK CONSERVATION] Excess water is supplied to the melt pond parameterization, which puts a fraction of it into the pond volume and allows the rest to run off into the ocean. +Sources of :math:`m_{liq}` are rain and snow melt; freezing of liquid water within the snowpack and runoff are sinks. Runoff and meltwater entering a snow layer (i.e., runoff from the layer above) are associated with vertical flow through the snow column. As in :cite:`Oleson10`, when the liquid water within a snow layer exceeds the layer’s holding capacity, the excess water is added to the underlying layer, limited by the effective porosity of the layer. The flow of water is assumed to be zero if the effective porosity of either of the two layers is less than the water-impermeable volumetric water content. [IS THIS TRUE? CHECK CONSERVATION] Excess water is supplied to the melt pond parameterization, which puts a fraction of it into the pond volume and allows the rest to run off into the ocean. -The snow mass fractions of precipitation, [CHECK] refrozen ice and old ice are saved for metamorphosing the snow grain radius. +The snow mass fractions of precipitation and old ice are saved for metamorphosing the snow grain radius. [CHECK]Code users will be able to choose whether heat and fresh water associated with liquid water in snow (or ponds) is held according to physical processes in the model or immediately fluxed to the ocean. The model will conserve both heat and water in either case. @@ -156,7 +156,7 @@ In the formation of depth hoar, dry snow kinetic metamorphism (TG metamorphism) The tracers :math:`m_{liq}` and :math:`m_{ice}` characterize the snow in each snow layer, for each ice category and horizontal grid cell. The model's meltpond volume covers a fraction of the grid cell and represents liquid in excess of :math:`m_{liq}`. The radiative effects of snow grain radius in the fraction of ice covered by pond volume are only calculated when the pond volume has not yet saturated the snow pack; otherwise, delta-Eddington transfer uses meltpond properties. Therefore, modelled changes in snow grain radii from metamorphism are designed specifically for the fraction without exposed (i.e. effective) melt ponds. -Following :cite:`Oleson10`, the new snow grain radius is computed as a weighted function of existing, new (freshly fallen)[CHECK, and refrozen] snow grain radii, using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density. +Following :cite:`Oleson10`, the new snow grain radius is computed as a weighted function of existing and new (freshly fallen) snow grain radii, using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density. From 4ab410788e80f8728b3a83ae9a1f7a47bea6f295 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 6 May 2021 20:11:33 -0600 Subject: [PATCH 29/47] TRSNOW 0 when not using advanced snow physics --- configuration/scripts/icepack.settings | 2 +- configuration/scripts/options/set_env.snw30percent | 2 ++ configuration/scripts/options/set_env.snwITDrdg | 1 + configuration/scripts/options/set_env.snwgrain | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configuration/scripts/icepack.settings b/configuration/scripts/icepack.settings index b5f3e2e9d..dab7276fc 100755 --- a/configuration/scripts/icepack.settings +++ b/configuration/scripts/icepack.settings @@ -49,7 +49,7 @@ setenv TRAGE 1 # set to 1 for ice age tracer setenv TRFY 1 # set to 1 for first-year ice area tracer setenv TRLVL 1 # set to 1 for level and deformed ice tracers setenv TRPND 1 # set to 1 for melt pond tracers -setenv TRSNOW 1 # set to 1 for snow metamorphism tracers +setenv TRSNOW 0 # set to 1 for snow metamorphism tracers setenv NTRAERO 1 # number of aerosol tracers # (up to max_aero in ice_domain_size.F90) # CESM uses 3 aerosol tracers diff --git a/configuration/scripts/options/set_env.snw30percent b/configuration/scripts/options/set_env.snw30percent index bc20eb455..2cb1d34ab 100644 --- a/configuration/scripts/options/set_env.snw30percent +++ b/configuration/scripts/options/set_env.snw30percent @@ -1,3 +1,5 @@ setenv NSNWLYR 3 # number of vertical layers in the snow +setenv TRSNOW 1 # set to 1 for advanced snow physics tracers + diff --git a/configuration/scripts/options/set_env.snwITDrdg b/configuration/scripts/options/set_env.snwITDrdg index 9540293c6..1937bbdb5 100644 --- a/configuration/scripts/options/set_env.snwITDrdg +++ b/configuration/scripts/options/set_env.snwITDrdg @@ -1,2 +1,3 @@ setenv NSNWLYR 3 # number of vertical layers in the snow +setenv TRSNOW 1 # set to 1 for advanced snow physics tracers diff --git a/configuration/scripts/options/set_env.snwgrain b/configuration/scripts/options/set_env.snwgrain index 9540293c6..1937bbdb5 100644 --- a/configuration/scripts/options/set_env.snwgrain +++ b/configuration/scripts/options/set_env.snwgrain @@ -1,2 +1,3 @@ setenv NSNWLYR 3 # number of vertical layers in the snow +setenv TRSNOW 1 # set to 1 for advanced snow physics tracers From 0bf5baede307a8b0c75a8cc0a4aa19c23432486d Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 May 2021 13:54:24 -0600 Subject: [PATCH 30/47] fix snow restarts, clean up unused flags --- configuration/driver/icedrv_restart.F90 | 8 ++++---- configuration/driver/icedrv_step.F90 | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/configuration/driver/icedrv_restart.F90 b/configuration/driver/icedrv_restart.F90 index 41990c00e..78337681b 100644 --- a/configuration/driver/icedrv_restart.F90 +++ b/configuration/driver/icedrv_restart.F90 @@ -517,10 +517,10 @@ subroutine read_restart_snow() write(nu_diag,*) 'min/max snow metamorphosis tracers' do k=1,nslyr - call write_restart_field(nu_restart,trcrn(:,nt_smice+k-1,:),ncat) - call write_restart_field(nu_restart,trcrn(:,nt_smliq+k-1,:),ncat) - call write_restart_field(nu_restart,trcrn(:,nt_rhos +k-1,:),ncat) - call write_restart_field(nu_restart,trcrn(:,nt_rsnw +k-1,:),ncat) + call read_restart_field(nu_restart,trcrn(:,nt_smice+k-1,:),ncat) + call read_restart_field(nu_restart,trcrn(:,nt_smliq+k-1,:),ncat) + call read_restart_field(nu_restart,trcrn(:,nt_rhos +k-1,:),ncat) + call read_restart_field(nu_restart,trcrn(:,nt_rsnw +k-1,:),ncat) enddo end subroutine read_restart_snow diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index dad6c3791..7c105e43e 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -153,8 +153,7 @@ subroutine step_therm1 (dt) nt_aero, nt_isosno, nt_isoice, nt_rsnw, nt_smice, nt_smliq logical (kind=log_kind) :: & - tr_iage, tr_FY, tr_aero, tr_iso, tr_pond, tr_pond_cesm, & - tr_pond_lvl, tr_pond_topo, calc_Tsfc, tr_snow + tr_iage, tr_FY, tr_aero, tr_iso, calc_Tsfc, tr_snow real (kind=dbl_kind), dimension(n_aero,2,ncat) :: & aerosno, aeroice ! kg/m^2 @@ -188,9 +187,7 @@ subroutine step_therm1 (dt) call icepack_query_tracer_flags( & tr_iage_out=tr_iage, tr_FY_out=tr_FY, & - tr_aero_out=tr_aero, tr_iso_out=tr_iso, tr_snow_out=tr_snow, & - tr_pond_out=tr_pond, tr_pond_cesm_out=tr_pond_cesm, & - tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo) + tr_aero_out=tr_aero, tr_iso_out=tr_iso, tr_snow_out=tr_snow) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) From a88f07e3a01d9c50dcabddb3fd12e99b164bb422 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 May 2021 15:54:40 -0600 Subject: [PATCH 31/47] updating snow documentation --- doc/source/science_guide/sg_snow.rst | 68 +++++++++++----------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index fac1e3f76..9b5e28d2f 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -9,22 +9,24 @@ Once deposited, the character and distribution of snow on sea ice depend on re-t The standard model configuration includes a basic snow formulation describing the essential effects of snow on sea ice, such as its albedo, vertical conduction, and growth/melt processes. It also incorporates more detailed processes such as snow-ice formation due to flooding and snow infiltration by melt water, which may form melt ponds. Several potentially important processes are not included in the standard configuration, such as compaction and redistribution of snow by wind and their effects on the thermal balance and on effective roughness. Snow metamorphism due to temperature gradients and liquid water content also are not included. -Setting ``tr_snow`` = ``.true.`` activates advanced snow physics parameterizations that represent the following processes: +Setting ``tr_snow`` = ``.true.`` activates advanced snow physics parameterizations that represent the following processes, each of which has its own namelist flag for flexible configuration: -1. Radiative effect of snow redistribution by wind with respect to ice topography, including snow compaction by wind +1. Radiative effects of snow redistribution by wind with respect to ice topography, including snow loss to leads and snow compaction by wind -2. Radiative effects of snow grain metamorphism (variable grain size) +2. Coupling effects associated with snow saturation and pond formation. -3. Coupling effects of including fresh water and heat associated with snow saturation - -Snow can be scoured from level ice, blowing into leads and ponds, or piling up on ridges. +3. Radiative effects of snow grain metamorphism (variable grain size) +Snow can be scoured from level ice, blowing into leads or piling up on ridges. The presence of liquid water in snow, such as rain or melt water, changes the surface albedo dramatically. It also alters the conductivity of the snow pack. These effects are associated mainly with the formation of depth hoar (change in grain size). -Except for the topo melt pond scheme, melt water and heat in ponds (which may be hidden within a partially saturated snow pack) are "virtual" in the sense that they are provided to the ocean model component immediately upon melting, even though the effects of the liquid water continue to be tracked as if it were retained on the ice. Retaining that water and heat in the sea ice component alters the timing, location and magnitude of fresh water runoff events into the ocean. - The standard model configuration assumes that the snow depth is uniform across each ice thickness category within a grid cell for the vertical thermodynamic calculation. However, there are separate radiation calculations for bare ice, snow-covered ice, and pond-covered ice; snow and ponds interact through snow saturation levels. Redistributing the snow alters these radiative calculations. +.. _snow_redistribution: + +Snow redistribution +------------------- + Because the thermodynamic schemes in CICE assume a uniform snow depth over each category, ignoring the fractions of level and deformed ice, effects of snow redistribution are included only via the delta-Eddington radiation scheme. The redistributed snow depth is used to determine the effective area of bare ice (for very small snow depths) and the effective area and depth of melt ponds over level ice. Once those areas are determined, the redistributed snow volume over them is known, from which the snow depth for the remaining snow-covered area can be computed and used for its radiation balance calculation. Two basic approaches are available for snow redistribution by wind, ``snwredist`` = ``bulk``, for which a user-defined parameter :math:`p` (``snwlvlfac``) determines the ratio of snow on ridges to that on level ice, and ``snwITDrdg``, in which snow can be compacted by the wind or eroded and redeposited on other thickness categories. For both, nonlocal redistribution of snow (i.e., between grid cells) is neglected, assuming that the difference between snow mass blowing into a grid cell and that blowing out is negligible, but snow can be blown into nearby leads and open water. @@ -34,18 +36,16 @@ Two basic approaches are available for snow redistribution by wind, ``snwredist` .. _snow_bulk: Bulk snow redistribution ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ -:cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m :math:`^{−2}` s :math:`^{−1}`, which accumulates snow only on the ice-covered area of the grid cell. +:cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m :math:`^{-2}` s :math:`^{-1}`, which accumulates snow only on the ice-covered area of the grid cell. There are two levels of sophistication at which this approach can be accomplished: (1) assuming the snow removed from the level ice area is deposited into leads, and (2) assuming the snow removed from the level ice area is deposited onto ridges. Case (1) affects both the radiative and thermodynamic calculations by reducing the total amount of snow on the ice. Case (2) affects the radiative calculation directly, by possibly exposing more bare ice or melt ponds, but it affects the thermodynamic (conduction) calculation only through the altered radiative absorption, since the snow is always assumed to be equally deep over both level and deformed ice for the thermodynamic calculation. -ECH CHECK WHAT IS DONE IN THE CODE - When ``snwredist`` = ``bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: .. math:: - f_{s}^\prime = {f_s a_{lvl} \left({1\over{1+p}}\right)}, + f_{s}^\prime = {f_s a_{lvl} \left({p\over{1+p}}\right)}, where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the level-ice tracer value, and primed quantities represent their modified values. @@ -57,14 +57,14 @@ Snow is redistributed between level and ridged ice within a single thickness cat .. math:: h_{rdg}^\prime = {{1 + p}\over {1+p(1-a_{lvl})}} h_{lvl}. -In the shortwave module for level-ice ponds, we create a new variable :math:`h_{lvl}^\prime`, ``hsnlvl``) for snow depth over the level ice, and replace ``hsn`` with ``hsnlvl`` for the snow infiltration calculation and for the calculation of snow depth over refrozen melt ponds. +In the shortwave module for level-ice ponds, we create a new variable :math:`h_{lvl}^\prime` (``hsnlvl``) for snow depth over the level ice, and replace ``hsn`` with ``hsnlvl`` for the snow infiltration calculation and for the calculation of snow depth over refrozen melt ponds. .. _snow_windredist: -Snow redistribution by wind ---------------------------- +Snow redistribution and compaction by wind +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Following :cite:`Lecomte15`, we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`\Phi` for snow mass as the sum of an erosion rate :math:`\Phi_E` and a redeposition rate :math:`\Phi_R` for each category of thickness :math:`h_i`: +Following :cite:`Lecomte15`, when ``snwredist`` = ``snwITDrdg`` we parameterize the amount of snow lost into the ocean through leads or redistributed to other thickness categories by defining the redistribution function :math:`\Phi` for snow mass as the sum of an erosion rate :math:`\Phi_E` and a redeposition rate :math:`\Phi_R` for each category of thickness :math:`h_i`: .. math:: \Phi_E = \left({\partial m \over \partial t}\right)_{erosion} = -{\gamma \over \sigma_{ITD}} \left(V-V^*\right){\rho_{max} - \rho_s \over \rho_{max}} @@ -82,23 +82,12 @@ In :cite:`Lecomte15`, the fraction of this suspended snow lost in leads is f = \left(1-a_i\right) \exp\left({\sigma_{ITD}\over\sigma_{ref}}\right), where the scale factor :math:`\sigma_{ref}=1` m and :math:`a_i` is the total ice area fraction within the grid cell. - -DELETE? -We also allow blowing snow to be caught in melt ponds, - -.. math:: - f = \left(1 - a_i - a_p a_{lvl} a_i\right) \exp\left({\sigma_{ITD}\over\sigma_{ref}}\right). - -If the ponds are frozen, the snow blown into them will accumulate on top of the pond ice; otherwise the new snow will contribute to any existing snow within the pond area. -END DELETE? [also 'or ponds' in the next line] - - -Thus, the snow mass that is redistribution on the ice (i.e., not lost in leads[DELETE? or ponds]) is +Thus, the snow mass that is redistribution on the ice (i.e., not lost in leads) is .. math:: \Phi_R \Delta t = a_i \left(1-f\right) \Phi_E \Delta t. -We [DELETE? further] extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, +We extend this approach by using the level and ridged ice thicknesses to compute the standard deviation of ice thickness across all categories. That is, .. math:: \sigma_{ITD}^2 = \sum_{n=1}^N a_{in} a_{lvln} \left(h_{ilvln}-\sum_{k=1}^N a_{ik}h_{ik}\right)^2 + a_{in} a_{rdgn} \left(h_{irdgn} - \sum_{k=1}^N a_{ik} h_{ik} \right)^2. @@ -117,16 +106,11 @@ where :math:`p \le a_{lvln}/a_{rdgn}`. The snow volume and energy state variables are updated in two steps, first for erosion of snow into suspension, then snow redeposition. When redepositing the snow, the snow energy is distributed among the snow layers affected by erosion, proportionally to the fraction of snow eroded. Finally, snow layer thicknesses are re-equalized, conserving snow energy. The fraction of suspended snow mass and energy lost in leads is added to the fresh water and heat fluxes for strict conservation. -.. _snow_windcompact: - -Snow compaction by wind ------------------------ - High wind speeds compact the upper portion of a snow pack into "wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. -:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{−3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{−3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. -For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{−3}` s -and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_s^{new} = \rho_s^{min} + 27.3 \max \left(V-10, 0\right)`. +:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{-3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{-3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. +For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{-3}` s +and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_{s}^{new} = \rho_{s}^{min} + 27.3 \max \left(V-10, 0\right)`. This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following :cite:`Sturm02`, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. .. _snow_liquid: @@ -135,15 +119,15 @@ Ice and liquid water mass in snow --------------------------------- The advanced snow physics option calculates ice and liquid water mass and effective snow grain radius, enabling them to interact with the radiation calculation. The mass of ice and liquid water in snow are implemented as tracers on snow volume layers and used for the snow grain metamorphism. -Together with snow volume, they also can be used to determine effective snow density as :math:`\rho_s^{eff} = m_{ice}+m_{liq} / h_s`. Note that :math:`m_{ice}+m_{liq}` (kg/m :math:`^2`) is the snow water equivalent. +Together with snow volume, they also can be used to determine effective snow density as :math:`\rho_s^{eff} = (m_{ice}+m_{liq}) / h_s`. Note that :math:`m_{ice}+m_{liq}` is the snow water equivalent (kg/m :math:`^2`). -Sources of :math:`m_{ice}` are snowfall, condensation, and freezing of liquid water within the snowpack; sinks are sublimation and melting. All of the sources and sinks of mice:math:`m_{ice}` are already computed in the code except for freezing of liquid water within the snow pack. +Sources of :math:`m_{ice}` are snowfall, condensation, and freezing of liquid water within the snowpack; sinks are sublimation and melting. All of the sources and sinks of :math:`m_{ice}` are already computed in the code except for freezing of liquid water within the snow pack. -Sources of :math:`m_{liq}` are rain and snow melt; freezing of liquid water within the snowpack and runoff are sinks. Runoff and meltwater entering a snow layer (i.e., runoff from the layer above) are associated with vertical flow through the snow column. As in :cite:`Oleson10`, when the liquid water within a snow layer exceeds the layer’s holding capacity, the excess water is added to the underlying layer, limited by the effective porosity of the layer. The flow of water is assumed to be zero if the effective porosity of either of the two layers is less than the water-impermeable volumetric water content. [IS THIS TRUE? CHECK CONSERVATION] Excess water is supplied to the melt pond parameterization, which puts a fraction of it into the pond volume and allows the rest to run off into the ocean. +Sources of :math:`m_{liq}` are rain and snow melt; freezing of liquid water within the snowpack and runoff are sinks. Runoff and meltwater entering a snow layer (i.e., runoff from the layer above) are associated with vertical flow through the snow column. As in :cite:`Oleson10`, when the liquid water within a snow layer exceeds the layer's holding capacity, the excess water is added to the underlying layer, limited by the effective porosity of the layer. When ``use_smliq_pnd`` is true, the excess water is supplied to the melt pond parameterization, which puts a fraction of it into the pond volume and allows the rest to run off into the ocean. The snow mass fractions of precipitation and old ice are saved for metamorphosing the snow grain radius. -[CHECK]Code users will be able to choose whether heat and fresh water associated with liquid water in snow (or ponds) is held according to physical processes in the model or immediately fluxed to the ocean. The model will conserve both heat and water in either case. +Except for the topo melt pond scheme, melt water and heat in ponds (which may be hidden within a partially saturated snow pack) are "virtual" in the sense that they are provided to the ocean model component immediately upon melting, even though the effects of the liquid water continue to be tracked as if it were retained on the ice. Retaining that water and heat in the sea ice component alters the timing, location and magnitude of fresh water runoff events into the ocean. All melt pond schemes include the meltwater effects, regardless of whether the liquid water is virtual. The advanced snow physics option allows the liquid water calculated by the snow metamorphism scheme to be used for melt pond calculations, replacing the snow melt and rainfall terms. .. _snow_metamorphosis: From 94bf11b34d54239b6b036140caeeeb4ebea88de9 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 28 May 2021 16:08:07 -0600 Subject: [PATCH 32/47] adding snow namelist info to science guide --- doc/source/science_guide/sg_snow.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 9b5e28d2f..7945fd106 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -108,9 +108,9 @@ The snow volume and energy state variables are updated in two steps, first for e High wind speeds compact the upper portion of a snow pack into "wind slab," a dense and more conductive medium that resists further drifting. An effective snow density is computed based on wind speed, which is then used to limit snow erosion of denser snow. -:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{-3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{-3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. -For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{-3}` s -and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_{s}^{new} = \rho_{s}^{min} + 27.3 \max \left(V-10, 0\right)`. +:cite:`Lecomte15` note that once snow is deposited, its density changes very little. During deposition, the density primarily falls into one of two types, wind slab for wind velocities greater than about 10 m/s, and loose snow for lighter winds. Their table 3 indicates densities for a variety of snow types. "Hard slab," deposited at :math:`V` = 13 m/s, has a density of :math:`\rho_s` = 403 kg m :math:`^{-3}` and "soft slab" is :math:`\rho_s` = 321 kg m :math:`^{-3}`, deposited at :math:`V` = 10 m/s. Linearly interpolating between these values, we have :math:`\rho_s = 27.3V + 47.7`. The slope is an adjustable namelist parameter, ``drhosdwind``. +For simplicity, we assign a minimum snow density of :math:`\rho_s^{min}` = 100 kg m :math:`^{-3}` s (``rhosmin``) +and add to it the gradient associated with wind speed from :cite:`Lecomte15` for wind speeds greater than 10 m/s: :math:`\rho_{s}^{new} = \rho_{s}^{min} + 27.3 \max \left(V-10, 0\right)`. The minimum wind speed to compact snow ``windmin`` is adjustable, and the maximum snow density is also a namelist parameter, ``rhosmax``. This density is merged with preexisting layer densities only if new snow falls. The thickness of the wind slab is the larger of the depth of newly fallen snow or the thickness of snow redeposited by the wind. Following :cite:`Sturm02`, density does not evolve further, other than by transport, unless additional snow falls at high enough wind speeds to compact the snow. .. _snow_liquid: @@ -134,13 +134,13 @@ Except for the topo melt pond scheme, melt water and heat in ponds (which may be Metamorphosis of snow grains ---------------------------- -Dynamic, effective snow radius, a snow volume tracer, evolves analytically as a function of snow temperature, temperature gradient, and density for radiative calculations using the delta-Eddington radiation scheme. +When ``snwgrain`` = ``.true.``, dynamic, effective snow radius, a snow volume tracer, evolves analytically as a function of snow temperature, temperature gradient, and density for radiative calculations using the delta-Eddington radiation scheme. Wet metamorphism changes both density (through volume change) and effective grain size; here we only consider changes in grain radius. In the formation of depth hoar, dry snow kinetic metamorphism (TG metamorphism) also increases the snow grain radius. The tracers :math:`m_{liq}` and :math:`m_{ice}` characterize the snow in each snow layer, for each ice category and horizontal grid cell. The model's meltpond volume covers a fraction of the grid cell and represents liquid in excess of :math:`m_{liq}`. The radiative effects of snow grain radius in the fraction of ice covered by pond volume are only calculated when the pond volume has not yet saturated the snow pack; otherwise, delta-Eddington transfer uses meltpond properties. Therefore, modelled changes in snow grain radii from metamorphism are designed specifically for the fraction without exposed (i.e. effective) melt ponds. -Following :cite:`Oleson10`, the new snow grain radius is computed as a weighted function of existing and new (freshly fallen) snow grain radii, using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density. +Following :cite:`Oleson10`, the new snow grain radius is computed as a weighted function of existing and new (freshly fallen, ``rsnw_fall``) snow grain radii, using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density. The maximum snow radius is a namelist option, ``rsnw_tmax``. From 846058d3c1288a1405f8a52ecec5882da15282a3 Mon Sep 17 00:00:00 2001 From: apcraig Date: Thu, 10 Jun 2021 12:37:58 -0600 Subject: [PATCH 33/47] update icepack to support snowtable better --- columnphysics/icepack_parameters.F90 | 187 +++++++++++++--- columnphysics/icepack_shortwave.F90 | 1 + columnphysics/icepack_snow.F90 | 308 ++++++++++++++++++++------ columnphysics/icepack_therm_mushy.F90 | 5 - doc/source/icepack_index.rst | 8 +- 5 files changed, 409 insertions(+), 100 deletions(-) diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index 166f4104c..736732a96 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -7,7 +7,8 @@ module icepack_parameters use icepack_kinds - use icepack_warnings, only: icepack_warnings_aborted + use icepack_warnings, only: icepack_warnings_aborted, & + icepack_warnings_add, icepack_warnings_setabort implicit none private @@ -317,7 +318,7 @@ module icepack_parameters character (len=char_len), public :: & snwredist = 'none', & ! type of snow redistribution - snw_aging_table = 'test' ! lookup table: 'snicar' or 'test' + snw_aging_table = 'test' ! lookup table: 'snicar' or 'test' or 'file' logical (kind=log_kind), public :: & use_smliq_pnd = .false. , & ! use liquid in snow for ponds @@ -340,10 +341,14 @@ module icepack_parameters isnw_rhos ! maximum snow density index ! dry snow aging parameters + real (kind=dbl_kind), dimension(:), allocatable, public :: & + snowage_rhos, & ! snowage table dimension data for rhos (kg/m^3) + snowage_Tgrd, & ! snowage table dimension data for temp gradient (deg K/m) + snowage_T ! snowage table dimension data for temperature (deg K) real (kind=dbl_kind), dimension(:,:,:), allocatable, public :: & - snowage_tau, & ! (10^-6 m) - snowage_kappa, & ! - snowage_drdt0 ! (10^-6 m/hr) + snowage_tau, & ! snowage table 3D data for tau (10^-6 m) + snowage_kappa, & ! snowage table 3D data for kappa (10^-6 m) + snowage_drdt0 ! snowage table 3D data for drdt0 (10^-6 m/hr) !----------------------------------------------------------------------- ! Parameters for biogeochemistry @@ -454,6 +459,7 @@ subroutine icepack_init_parameters( & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & rhosnew_in, rhosmin_in, rhosmax_in, windmin_in, drhosdwind_in, & snwlvlfac_in, isnw_T_in, isnw_Tgrd_in, isnw_rhos_in, & + snowage_rhos_in, snowage_Tgrd_in, snowage_T_in, & snowage_tau_in, snowage_kappa_in, snowage_drdt0_in, & snw_aging_table_in) @@ -513,7 +519,7 @@ subroutine icepack_init_parameters( & ! 1 = Bitz and Lipscomb 1999 ! 2 = mushy layer theory - character (char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & conduct_in, & ! 'MU71' or 'bubbly' fbot_xfer_type_in ! transfer coefficient type for ice-ocean heat flux @@ -538,7 +544,7 @@ subroutine icepack_init_parameters( & phi_c_slow_mode_in , & ! liquid fraction porosity cutoff for slow mode phi_i_mushy_in ! liquid fraction of congelation ice - character(len=char_len), intent(in), optional :: & + character(len=*), intent(in), optional :: & tfrz_option_in ! form of ocean freezing temperature ! 'minus1p8' = -1.8 C ! 'linear_salt' = -depressT * sss @@ -561,7 +567,7 @@ subroutine icepack_init_parameters( & awtvdf_in, & ! visible, diffuse awtidf_in ! near IR, diffuse - character (len=char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & shortwave_in, & ! shortwave method, 'ccsm3' or 'dEdd' albedo_type_in ! albedo parameterization, 'ccsm3' or 'constant' ! shortwave='dEdd' overrides this parameter @@ -629,7 +635,7 @@ subroutine icepack_init_parameters( & qqqocn_in, & ! for qsat over ocn TTTocn_in ! for qsat over ocn - character (len=char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & atmbndy_in ! atmo boundary method, 'default' ('ccsm3') or 'constant' logical (kind=log_kind), intent(in), optional :: & @@ -669,14 +675,14 @@ subroutine icepack_init_parameters( & logical (kind=log_kind), intent(in), optional :: & wave_spec_in ! if true, use wave forcing - character (len=char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & wave_spec_type_in ! type of wave spectrum forcing !----------------------------------------------------------------------- ! Parameters for biogeochemistry !----------------------------------------------------------------------- - character(char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & bgc_flux_type_in ! type of ocean-ice piston velocity ! 'constant', 'Jin2006' @@ -737,7 +743,7 @@ subroutine icepack_init_parameters( & hs0_in ! snow depth for transition to bare sea ice (m) ! level-ice ponds - character (len=char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & frzpnd_in ! pond refreezing parameterization real (kind=dbl_kind), intent(in), optional :: & @@ -755,7 +761,7 @@ subroutine icepack_init_parameters( & ! Parameters for snow redistribution, metamorphosis !----------------------------------------------------------------------- - character (len=char_len), intent(in), optional :: & + character (len=*), intent(in), optional :: & snwredist_in, & ! type of snow redistribution snw_aging_table_in ! snow aging lookup table @@ -771,11 +777,18 @@ subroutine icepack_init_parameters( & rhosmax_in, & ! maximum snow density (kg/m^3) windmin_in, & ! minimum wind speed to compact snow (m/s) drhosdwind_in, & ! wind compaction factor (kg s/m^4) - snwlvlfac_in, & ! fractional increase in snow depth + snwlvlfac_in ! fractional increase in snow depth + + integer (kind=int_kind), intent(in), optional :: & isnw_T_in, & ! maxiumum temperature index isnw_Tgrd_in, & ! maxiumum temperature gradient index isnw_rhos_in ! maxiumum snow density index + real (kind=dbl_kind), dimension(:), intent(in), optional :: & + snowage_rhos_in, & ! snowage dimension data + snowage_Tgrd_in, & ! + snowage_T_in ! + real (kind=dbl_kind), dimension(:,:,:), intent(in), optional :: & snowage_tau_in, & ! (10^-6 m) snowage_kappa_in, &! @@ -911,9 +924,109 @@ subroutine icepack_init_parameters( & if (present(isnw_T_in) ) isnw_T = isnw_T_in if (present(isnw_Tgrd_in) ) isnw_Tgrd = isnw_Tgrd_in if (present(isnw_rhos_in) ) isnw_rhos = isnw_rhos_in - if (present(snowage_tau_in) ) snowage_tau = snowage_tau_in - if (present(snowage_kappa_in) ) snowage_kappa = snowage_kappa_in - if (present(snowage_drdt0_in) ) snowage_drdt0 = snowage_drdt0_in + + ! check array sizes and re/allocate if necessary + if (present(snowage_rhos_in) ) then + if (size(snowage_rhos_in) /= isnw_rhos) then + call icepack_warnings_add(subname//' incorrect size of snowage_rhos_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_rhos)) then + allocate(snowage_rhos(isnw_rhos)) + snowage_rhos = snowage_rhos_in + elseif (size(snowage_rhos) /= isnw_rhos) then + deallocate(snowage_rhos) + allocate(snowage_rhos(isnw_rhos)) + snowage_rhos = snowage_rhos_in + else + snowage_rhos = snowage_rhos_in + endif + endif + + ! check array sizes and re/allocate if necessary + if (present(snowage_Tgrd_in) ) then + if (size(snowage_Tgrd_in) /= isnw_Tgrd) then + call icepack_warnings_add(subname//' incorrect size of snowage_Tgrd_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_Tgrd)) then + allocate(snowage_Tgrd(isnw_Tgrd)) + snowage_Tgrd = snowage_Tgrd_in + elseif (size(snowage_Tgrd) /= isnw_Tgrd) then + deallocate(snowage_Tgrd) + allocate(snowage_Tgrd(isnw_Tgrd)) + snowage_Tgrd = snowage_Tgrd_in + else + snowage_Tgrd = snowage_Tgrd_in + endif + endif + + ! check array sizes and re/allocate if necessary + if (present(snowage_T_in) ) then + if (size(snowage_T_in) /= isnw_T) then + call icepack_warnings_add(subname//' incorrect size of snowage_T_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_T)) then + allocate(snowage_T(isnw_T)) + snowage_T = snowage_T_in + elseif (size(snowage_T) /= isnw_T) then + deallocate(snowage_T) + allocate(snowage_T(isnw_T)) + snowage_T = snowage_T_in + else + snowage_T = snowage_T_in + endif + endif + + ! check array sizes and re/allocate if necessary + if (present(snowage_tau_in) ) then + if (size(snowage_tau_in) /= isnw_T*isnw_Tgrd*isnw_rhos) then + call icepack_warnings_add(subname//' incorrect size of snowage_tau_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_tau)) then + allocate(snowage_tau(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_tau = snowage_tau_in + elseif (size(snowage_tau) /= isnw_T*isnw_Tgrd*isnw_rhos) then + deallocate(snowage_tau) + allocate(snowage_tau(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_tau = snowage_tau_in + else + snowage_tau = snowage_tau_in + endif + endif + + ! check array sizes and re/allocate if necessary + if (present(snowage_kappa_in) ) then + if (size(snowage_kappa_in) /= isnw_T*isnw_Tgrd*isnw_rhos) then + call icepack_warnings_add(subname//' incorrect size of snowage_kappa_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_kappa)) then + allocate(snowage_kappa(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_kappa = snowage_kappa_in + elseif (size(snowage_kappa) /= isnw_T*isnw_Tgrd*isnw_rhos) then + deallocate(snowage_kappa) + allocate(snowage_kappa(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_kappa = snowage_kappa_in + else + snowage_kappa = snowage_kappa_in + endif + endif + + ! check array sizes and re/allocate if necessary + if (present(snowage_drdt0_in) ) then + if (size(snowage_drdt0_in) /= isnw_T*isnw_Tgrd*isnw_rhos) then + call icepack_warnings_add(subname//' incorrect size of snowage_drdt0_in') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + elseif (.not.allocated(snowage_drdt0)) then + allocate(snowage_drdt0(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_drdt0 = snowage_drdt0_in + elseif (size(snowage_drdt0) /= isnw_T*isnw_Tgrd*isnw_rhos) then + deallocate(snowage_drdt0) + allocate(snowage_drdt0(isnw_T,isnw_Tgrd,isnw_rhos)) + snowage_drdt0 = snowage_drdt0_in + else + snowage_drdt0 = snowage_drdt0_in + endif + endif + if (present(bgc_flux_type_in) ) bgc_flux_type = bgc_flux_type_in if (present(z_tracers_in) ) z_tracers = z_tracers_in if (present(scale_bgc_in) ) scale_bgc = scale_bgc_in @@ -1009,6 +1122,7 @@ subroutine icepack_query_parameters( & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & rhosnew_out, rhosmin_out, rhosmax_out, windmin_out, drhosdwind_out, & snwlvlfac_out, isnw_T_out, isnw_Tgrd_out, isnw_rhos_out, & + snowage_rhos_out, snowage_Tgrd_out, snowage_T_out, & snowage_tau_out, snowage_kappa_out, snowage_drdt0_out, & snw_aging_table_out) @@ -1077,7 +1191,7 @@ subroutine icepack_query_parameters( & ! 1 = Bitz and Lipscomb 1999 ! 2 = mushy layer theory - character (char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & conduct_out, & ! 'MU71' or 'bubbly' fbot_xfer_type_out ! transfer coefficient type for ice-ocean heat flux @@ -1102,7 +1216,7 @@ subroutine icepack_query_parameters( & phi_c_slow_mode_out , & ! liquid fraction porosity cutoff for slow mode phi_i_mushy_out ! liquid fraction of congelation ice - character(len=char_len), intent(out), optional :: & + character(len=*), intent(out), optional :: & tfrz_option_out ! form of ocean freezing temperature ! 'minus1p8' = -1.8 C ! 'linear_salt' = -depressT * sss @@ -1125,7 +1239,7 @@ subroutine icepack_query_parameters( & awtvdf_out, & ! visible, diffuse awtidf_out ! near IR, diffuse - character (len=char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & shortwave_out, & ! shortwave method, 'ccsm3' or 'dEdd' albedo_type_out ! albedo parameterization, 'ccsm3' or 'constant' ! shortwave='dEdd' overrides this parameter @@ -1193,7 +1307,7 @@ subroutine icepack_query_parameters( & qqqocn_out, & ! for qsat over ocn TTTocn_out ! for qsat over ocn - character (len=char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & atmbndy_out ! atmo boundary method, 'default' ('ccsm3') or 'constant' logical (kind=log_kind), intent(out), optional :: & @@ -1233,15 +1347,15 @@ subroutine icepack_query_parameters( & logical (kind=log_kind), intent(out), optional :: & wave_spec_out ! if true, use wave forcing - character (len=char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & wave_spec_type_out ! type of wave spectrum forcing !----------------------------------------------------------------------- ! Parameters for biogeochemistry !----------------------------------------------------------------------- - character(char_len), intent(out), optional :: & - bgc_flux_type_out ! type of ocean-ice piston velocity + character (len=*), intent(out), optional :: & + bgc_flux_type_out ! type of ocean-ice piston velocity ! 'constant', 'Jin2006' logical (kind=log_kind), intent(out), optional :: & @@ -1301,7 +1415,7 @@ subroutine icepack_query_parameters( & hs0_out ! snow depth for transition to bare sea ice (m) ! level-ice ponds - character (len=char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & frzpnd_out ! pond refreezing parameterization real (kind=dbl_kind), intent(out), optional :: & @@ -1319,7 +1433,7 @@ subroutine icepack_query_parameters( & ! Parameters for snow redistribution, metamorphosis !----------------------------------------------------------------------- - character (len=char_len), intent(out), optional :: & + character (len=*), intent(out), optional :: & snwredist_out, & ! type of snow redistribution snw_aging_table_out ! snow aging lookup table @@ -1335,11 +1449,18 @@ subroutine icepack_query_parameters( & rhosmax_out, & ! maximum snow density (kg/m^3) windmin_out, & ! minimum wind speed to compact snow (m/s) drhosdwind_out, & ! wind compaction factor (kg s/m^4) - snwlvlfac_out, & ! fractional increase in snow depth + snwlvlfac_out ! fractional increase in snow depth + + integer (kind=int_kind), intent(out), optional :: & isnw_T_out, & ! maxiumum temperature index isnw_Tgrd_out, & ! maxiumum temperature gradient index isnw_rhos_out ! maxiumum snow density index + real (kind=dbl_kind), dimension(:), intent(out), optional :: & + snowage_rhos_out, & ! snowage dimension data + snowage_Tgrd_out, & ! + snowage_T_out ! + real (kind=dbl_kind), dimension(:,:,:), intent(out), optional :: & snowage_tau_out, & ! (10^-6 m) snowage_kappa_out, &! @@ -1515,6 +1636,9 @@ subroutine icepack_query_parameters( & if (present(isnw_T_out) ) isnw_T_out = isnw_T if (present(isnw_Tgrd_out) ) isnw_Tgrd_out = isnw_Tgrd if (present(isnw_rhos_out) ) isnw_rhos_out = isnw_rhos + if (present(snowage_rhos_out) ) snowage_rhos_out = snowage_rhos + if (present(snowage_Tgrd_out) ) snowage_Tgrd_out = snowage_Tgrd + if (present(snowage_T_out) ) snowage_T_out = snowage_T if (present(snowage_tau_out) ) snowage_tau_out = snowage_tau if (present(snowage_kappa_out) ) snowage_kappa_out= snowage_kappa if (present(snowage_drdt0_out) ) snowage_drdt0_out= snowage_drdt0 @@ -1713,9 +1837,12 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " isnw_T = ", isnw_T write(iounit,*) " isnw_Tgrd = ", isnw_Tgrd write(iounit,*) " isnw_rhos = ", isnw_rhos - write(iounit,*) " snowage_tau = ", snowage_tau - write(iounit,*) " snowage_kappa = ", snowage_kappa - write(iounit,*) " snowage_drdt0 = ", snowage_drdt0 + write(iounit,*) " snowage_rhos = ", snowage_rhos(1) + write(iounit,*) " snowage_Tgrd = ", snowage_Tgrd(1) + write(iounit,*) " snowage_T = ", snowage_T(1) + write(iounit,*) " snowage_tau = ", snowage_tau(1,1,1) + write(iounit,*) " snowage_kappa = ", snowage_kappa(1,1,1) + write(iounit,*) " snowage_drdt0 = ", snowage_drdt0(1,1,1) write(iounit,*) " bgc_flux_type = ", bgc_flux_type write(iounit,*) " z_tracers = ", z_tracers write(iounit,*) " scale_bgc = ", scale_bgc diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 5eeecd6e5..7f3088e7e 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -1050,6 +1050,7 @@ subroutine run_dEdd(dt, ncat, & hs0, hsnlvl, & rhosnwn(:), rsnwn(:), & rsnow(:,n)) + if (icepack_warnings_aborted(subname)) return endif ! snwredist fpn = c0 ! fraction of ice covered in pond diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index a714d4fa3..2139dbef4 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -14,10 +14,12 @@ module icepack_snow use icepack_parameters, only: snwredist, rsnw_fall, rsnw_tmax, rhosnew use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind use icepack_parameters, only: isnw_T, isnw_Tgrd, isnw_rhos + use icepack_parameters, only: snowage_rhos, snowage_Tgrd, snowage_T use icepack_parameters, only: snowage_tau, snowage_kappa, snowage_drdt0 use icepack_parameters, only: snw_aging_table use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort + use icepack_warnings, only: icepack_warnings_aborted implicit none private @@ -28,11 +30,18 @@ module icepack_snow S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976) S_wet= 4.22e-5_dbl_kind ! (um^3/s) wet metamorphism parameters - ! shift in indices for aging test table - integer (kind=int_kind) :: & - iT_shift, & ! shift in maximum temperature index - iTgrd_shift, & ! shift in maximum temperature gradient index - irhos_shift ! shift in maximum snow density index + real (kind=dbl_kind) :: & + min_rhos, & ! snowtable axis data, assumes linear data + del_rhos, & + min_Tgrd, & + del_Tgrd, & + min_T , & + del_T + + logical (kind=log_kind) :: & + lin_rhos = .false., & ! flag to specify whether the snowtable dimensions are linear + lin_Tgrd = .false., & ! this will allow quick lookup + lin_T = .false. !======================================================================= @@ -51,33 +60,96 @@ subroutine icepack_init_snow ! local variables + integer (kind=int_kind) :: n + character (len=*),parameter :: subname='(icepack_init_snow)' !----------------------------------------------------------------- ! Snow metamorphism lookup table !----------------------------------------------------------------- + ! if snw_aging_table = 'snicar' + ! best-fit parameters are read from a table (netcdf) + ! snowage_tau, snowage_kappa, snowage_drdt0 + ! 11 temperatures from 223.15 to 273.15 K by 5.0 + ! 31 temperature gradients from 0 to 300 K/m by 10 + ! 8 snow densities from 50 to 400 kg/m3 by 50 + + ! if snw_aging_table = 'test' + ! for testing Icepack without netcdf, + ! use a subsampled, hard-coded table + ! 5 temperatures from 243.15 by 5.0 K + ! 5 temperature gradients from 0 to 40 K/m by 10 + ! 1 snow density at 300 kg/m3 + + ! if snw_aging_table = 'file' + ! all data has to be passed into icepack_parameters + + ! tcraig, should be 223.15 and 243.15 below + if (snwgrain) then if (trim(snw_aging_table) == 'snicar') then ! read netcdf file - isnw_T = 11 ! maxiumum temperature index - isnw_Tgrd = 31 ! maxiumum temperature gradient index isnw_rhos = 8 ! maxiumum snow density index + isnw_Tgrd = 31 ! maxiumum temperature gradient index + isnw_T = 11 ! maxiumum temperature index + min_rhos = 50.0_dbl_kind ! snowtable dimension data + del_rhos = 50.0_dbl_kind + lin_rhos = .true. + min_Tgrd = 0.0_dbl_kind + del_Tgrd = 10.0_dbl_kind + lin_Tgrd = .true. + min_T = 223.0_dbl_kind + del_T = 5.0_dbl_kind + lin_T = .true. allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T)) allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T)) - iT_shift = 0 ! use entire table - iTgrd_shift = 0 ! - irhos_shift = 0 ! + allocate (snowage_rhos (isnw_rhos)) + allocate (snowage_Tgrd (isnw_Tgrd)) + allocate (snowage_T (isnw_T)) + do n = 1, isnw_rhos + snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos + enddo + do n = 1, isnw_Tgrd + snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd + enddo + do n = 1, isnw_T + snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T + enddo + + elseif (trim(snw_aging_table) == 'file') then + isnw_rhos = -1 ! maxiumum snow density index + isnw_Tgrd = -1 ! maxiumum temperature gradient index + isnw_T = -1 ! maxiumum temperature index + elseif (trim(snw_aging_table) == 'test') then - isnw_T = 5 ! maxiumum temperature index - isnw_Tgrd = 5 ! maxiumum temperature gradient index isnw_rhos = 1 ! maxiumum snow density index + isnw_Tgrd = 5 ! maxiumum temperature gradient index + isnw_T = 5 ! maxiumum temperature index + min_rhos = 300.0_dbl_kind ! snowtable dimension data + del_rhos = 50.0_dbl_kind + lin_rhos = .true. + min_Tgrd = 0.0_dbl_kind + del_Tgrd = 10.0_dbl_kind + lin_Tgrd = .true. + min_T = 243.0_dbl_kind + del_T = 5.0_dbl_kind + lin_T = .true. allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T)) allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T)) - iT_shift = 4 ! index adjustments for subset of table - iTgrd_shift = 0 ! - irhos_shift = 5 ! + allocate (snowage_rhos (isnw_rhos)) + allocate (snowage_Tgrd (isnw_Tgrd)) + allocate (snowage_T (isnw_T)) + do n = 1, isnw_rhos + snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos + enddo + do n = 1, isnw_Tgrd + snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd + enddo + do n = 1, isnw_T + snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T + enddo ! Subset of dry snow aging parameters snowage_tau = reshape((/ & @@ -107,6 +179,10 @@ subroutine icepack_init_snow 3.85605846, 3.85668001, 3.85844559, 3.86073682, 3.863199, & 5.0861907, 5.08765668, 5.09200195, 5.09665276, 5.10079895/), & (/isnw_rhos,isnw_Tgrd,isnw_T/)) + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: snw_aging_table value') + return endif endif @@ -207,6 +283,7 @@ subroutine icepack_step_snow(dt, nilyr, & smice, smliq, & rhos_effn, rhos_eff, & rhos_cmpn, rhos_cmp) + if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- ! Redistribute snow based on wind @@ -224,6 +301,7 @@ subroutine icepack_step_snow(dt, nilyr, & fresh, fhocn, & fsloss, rhos_cmpn, & fsnow) + if (icepack_warnings_aborted(subname)) return endif vsno = c0 @@ -260,6 +338,7 @@ subroutine icepack_step_snow(dt, nilyr, & Tsfc, zTin1, & hsn, zqsn, & smice, smliq) + if (icepack_warnings_aborted(subname)) return endif end subroutine icepack_step_snow @@ -655,6 +734,7 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & zs1(:), zs2(:), & hslyr, hsn_new(n), & zqsn(:,n)) + if (icepack_warnings_aborted(subname)) return endif ! nslyr > 1 endif ! |dhsn| > puny endif ! ain > puny @@ -841,6 +921,7 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & drsnw_dry, zqsn(:,n), Tsfc(n), & zTin(n), hsn(n), hin(n), & smice(:,n), smliq(:,n)) + if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- ! wet metamorphism @@ -848,6 +929,7 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & do k = 1,nslyr call snow_wet_metamorph (dt, drsnw_wet(k), rsnw(k,n), & smice(k,n), smliq(k,n)) + if (icepack_warnings_aborted(subname)) return rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k)) enddo @@ -870,18 +952,18 @@ end subroutine update_snow_radius subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & Tsfc, zTin1, hsn, hin, smice, smliq) - ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that - ! depend on snow temperature, temperature gradient, and density, - ! that are derived from the microphysical model described in: - ! Flanner and Zender (2006), Linking snowpack microphysics and albedo - ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834. - ! The parametric equation has the form: - ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where: - ! r is the effective radius, - ! tau and kappa are best-fit parameters, - ! drdt_0 is the initial rate of change of effective radius, and - ! dr_fresh is the difference between the current and fresh snow states - ! (r_current - r_fresh). + ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that + ! depend on snow temperature, temperature gradient, and density, + ! that are derived from the microphysical model described in: + ! Flanner and Zender (2006), Linking snowpack microphysics and albedo + ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834. + ! The parametric equation has the form: + ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where: + ! r is the effective radius, + ! tau and kappa are best-fit parameters, + ! drdt_0 is the initial rate of change of effective radius, and + ! dr_fresh is the difference between the current and fresh snow states + ! (r_current - r_fresh). integer (kind=int_kind), intent(in) :: & nslyr, & ! number of snow layers @@ -930,10 +1012,51 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & dzi, & ! ice layer thickness (m) dz ! dzs + dzi (m) + logical (kind=log_kind) :: & + first_call = .true. ! first call flag + + character (char_len) :: & + string ! generic string for writing messages + character (len=*),parameter :: subname='(snow_dry_metamorph)' -! Needed for variable snow density not currently modeled -! calculate density based on liquid and ice content of snow + !----------------------------------------------------------------- + ! On the first call, check that the table is setup properly + ! Check sizes of 1D and 3D data + ! Check that the 1D data is regularly spaced and set min, del, and lin values + ! for each 1D variable. This info will be used later for the table lookup. + !----------------------------------------------------------------- + + if (first_call) then + if (isnw_rhos < 1 .or. isnw_Tgrd < 1 .or. isnw_T < 1 .or. & + size(snowage_rhos) /= isnw_rhos .or. & + size(snowage_Tgrd) /= isnw_Tgrd .or. & + size(snowage_T) /= isnw_T .or. & + size(snowage_tau) /= isnw_rhos*isnw_Tgrd*isnw_T .or. & + size(snowage_kappa) /= isnw_rhos*isnw_Tgrd*isnw_T .or. & + size(snowage_drdt0) /= isnw_rhos*isnw_Tgrd*isnw_T) then + write(string,'(a,3i4)') subname//' snowtable size1 = ',isnw_rhos, isnw_Tgrd, isnw_T + call icepack_warnings_add(string) + write(string,'(a,3i4)') subname//' snowtable size2 = ',size(snowage_rhos),size(snowage_Tgrd),size(snowage_T) + call icepack_warnings_add(string) + write(string,'(a,3i9)') subname//' snowtable size3 = ',size(snowage_tau),size(snowage_kappa),size(snowage_drdt0) + call icepack_warnings_add(string) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: arrays sizes error') + return + endif + call snowtable_check_dimension(snowage_rhos, min_rhos, del_rhos, lin_rhos) + if (icepack_warnings_aborted(subname)) return + call snowtable_check_dimension(snowage_Tgrd, min_Tgrd, del_Tgrd, lin_Tgrd) + if (icepack_warnings_aborted(subname)) return + call snowtable_check_dimension(snowage_T , min_T , del_T , lin_T ) + if (icepack_warnings_aborted(subname)) return + endif + + !----------------------------------------------------------------- + ! Needed for variable snow density not currently modeled + ! calculate density based on liquid and ice content of snow + !----------------------------------------------------------------- drsnw_dry(:) = c0 zTsn(:) = c0 @@ -966,43 +1089,56 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & zdTdz(nslyr) = min(c10*isnw_Tgrd, zdTdz(nslyr)) endif - ! if snw_aging_table = 'snicar' - ! best-fit parameters are read from a table (netcdf) - ! snowage_tau, snowage_kappa, snowage_drdt0 - ! 11 temperatures from 225 to 273 K - ! 31 temperature gradients from 0 to 300 K/m - ! 8 snow densities from 0 to 350 kg/m3 + do k = 1, nslyr + zrhos(k) = smice(k) + smliq(k) - ! if snw_aging_table = 'test' - ! for testing Icepack without netcdf, - ! use a subsampled, hard-coded table - ! 5 temperatures - ! 5 temperature gradients - ! 1 snow density + !----------------------------------------------------------------- + ! best-fit table indices: + ! Will abort if 1D data is not regularly spaced (lin_* flag must be true) + ! Leave option for doing a search into non regularly spaced 1D data in the future + ! via a binary search or similar. + !----------------------------------------------------------------- - do k = 1, nslyr - zrhos(k) = smice(k) + smliq(k) - - ! best-fit table indices: - T_idx = nint(abs(zTsn(k)+ Tffresh - 223.0_dbl_kind) / 5.0_dbl_kind, kind=int_kind) - iT_shift - Tgrd_idx = nint(zdTdz(k) / 10.0_dbl_kind, kind=int_kind) - iTgrd_shift - !rhos_idx = nint(zrhos(k)-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) - irhos_shift ! variable density - rhos_idx = nint((rhos-50.0_dbl_kind) / 50.0_dbl_kind, kind=int_kind) - irhos_shift ! fixed density - - ! boundary check: - T_idx = min(isnw_T, max(1,T_idx+1)) - Tgrd_idx = min(isnw_Tgrd, max(1,Tgrd_idx+1)) - rhos_idx = min(isnw_rhos, max(1,rhos_idx+1)) - - bst_tau = snowage_tau (rhos_idx,Tgrd_idx,T_idx) - bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx) - bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx) - - ! change in snow effective radius, using best-fit parameters - dr_fresh = max(c0,rsnw(k)-rsnw_fall) - drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))& - * (dt/3600.0_dbl_kind) - enddo + if (lin_rhos) then + rhos_idx = nint( (rhos - min_rhos) / del_rhos, kind=int_kind) + 1 + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for rhos not supported yet') + return + endif + + if (lin_Tgrd) then + Tgrd_idx = nint( (zdTdz(k) - min_Tgrd) / del_Tgrd, kind=int_kind) + 1 + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for Tgrd not supported yet') + return + endif + + if (lin_T) then + T_idx = nint(abs(zTsn(k)+ Tffresh - min_T ) / del_T , kind=int_kind) + 1 + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for T not supported yet') + return + endif + + ! boundary check: + rhos_idx = min(isnw_rhos, max(1,rhos_idx)) + Tgrd_idx = min(isnw_Tgrd, max(1,Tgrd_idx)) + T_idx = min(isnw_T , max(1,T_idx )) + + bst_tau = snowage_tau (rhos_idx,Tgrd_idx,T_idx) + bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx) + bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx) + + ! change in snow effective radius, using best-fit parameters + dr_fresh = max(c0,rsnw(k)-rsnw_fall) + drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))& + * (dt/3600.0_dbl_kind) + enddo + + first_call = .false. end subroutine snow_dry_metamorph @@ -1047,6 +1183,50 @@ end subroutine snow_wet_metamorph !======================================================================= +! Analyze 1D array for regular spacing for snow table lookup +! and set the min, del, and lin values. +! Tolerance for regular spacing set at 1.0e-8 * typical array value + + subroutine snowtable_check_dimension(array, min_fld, del_fld, lin_fld) + + real (kind=dbl_kind), intent(in), dimension(:) :: & + array ! array to check + + real (kind=dbl_kind), intent(inout) :: & + min_fld, & ! min value if linear + del_fld ! delta value if linear + + logical (kind=log_kind), intent(inout) :: & + lin_fld ! linear flag + + ! local temporary variables + + integer (kind=int_kind) :: n, asize + + real (kind=dbl_kind) :: tolerance ! tolerance for linear checking + + character (len=*),parameter :: subname='(snowtable_check_dimension)' + + asize = size(array) + + if (asize == 1) then + min_fld = array(1) + del_fld = array(1) ! arbitrary + lin_fld = .true. + else + lin_fld = .true. + min_fld = array(1) + del_fld = array(2) - array(1) + tolerance = 1.0e-08_dbl_kind * max(abs(array(1)),abs(array(2))) ! relative to typical value + do n = 3,asize + if (abs(array(n) - array(n-1) - del_fld) > tolerance) lin_fld = .false. + enddo + endif + + end subroutine snowtable_check_dimension + +!======================================================================= + ! Conversions between ice mass, liquid water mass in snow subroutine drain_snow (dt, nslyr, vsnon, aicen, & diff --git a/columnphysics/icepack_therm_mushy.F90 b/columnphysics/icepack_therm_mushy.F90 index ac2d4d1dc..f34947579 100644 --- a/columnphysics/icepack_therm_mushy.F90 +++ b/columnphysics/icepack_therm_mushy.F90 @@ -485,7 +485,6 @@ subroutine two_stage_solver_snow(nilyr, nslyr, & Spond, sss, & q, dSdt, & w ) - if (icepack_warnings_aborted(subname)) return ! halt if solver failed if (icepack_warnings_aborted(subname)) return @@ -531,7 +530,6 @@ subroutine two_stage_solver_snow(nilyr, nslyr, & Spond, sss, & q, dSdt, & w ) - if (icepack_warnings_aborted(subname)) return ! halt if solver failed if (icepack_warnings_aborted(subname)) return @@ -586,7 +584,6 @@ subroutine two_stage_solver_snow(nilyr, nslyr, & q, dSdt, & w ) - if (icepack_warnings_aborted(subname)) return ! halt if solver failed if (icepack_warnings_aborted(subname)) return @@ -635,7 +632,6 @@ subroutine two_stage_solver_snow(nilyr, nslyr, & Spond, sss, & q, dSdt, & w ) - if (icepack_warnings_aborted(subname)) return ! halt if solver failed if (icepack_warnings_aborted(subname)) return @@ -798,7 +794,6 @@ subroutine two_stage_solver_nosnow(nilyr, nslyr, & Spond, sss, & q, dSdt, & w ) - if (icepack_warnings_aborted(subname)) return ! halt if solver failed if (icepack_warnings_aborted(subname)) return diff --git a/doc/source/icepack_index.rst b/doc/source/icepack_index.rst index e1c1816fd..f3a833a6a 100755 --- a/doc/source/icepack_index.rst +++ b/doc/source/icepack_index.rst @@ -411,7 +411,13 @@ either Celsius or Kelvin units). "shortwave", ":math:`\bullet` flag for shortwave parameterization ('default' or 'dEdd')", "" "sil", "silicate concentration", "mmol/m\ :math:`^3`" "sk_l", "skeletal layer thickness", "0.03 m" - "snoice", "snow-ice formation", "m" + "snowage_drdt0", "snowage table 3D data for drdt0 (10^-6 m/hr)", "" + "snowage_kappa", "snowage table 3D data for kappa (10^-6 m)", "" + "snowage_rhos", "snowage table dimension data for rhos (kg/m^3)", "" + "snowage_T", "snowage table dimension data for temperature (deg K)", "" + "snowage_tau", "snowage table 3D data for tau (10^-6 m)", "" + "snowage_Tgrd", "snowage table dimension data for temp gradient (deg K/m)", "" + "snoice"", "snow-ice formation", "m"" "snowpatch", "length scale for parameterizing nonuniform snow coverage", "0.02 m" "skl_bgc", ":math:`\bullet` biogeochemistry on/off", "" "spval", "special value (single precision)", ":math:`10^{30}`", "" From ce018531986c47a8c92cb1982a4a37fab5fe76bb Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 17 Jun 2021 21:20:58 -0600 Subject: [PATCH 34/47] adjust parameter values, test options --- columnphysics/icepack_snow.F90 | 6 ++---- configuration/scripts/tests/base_suite.ts | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index 2139dbef4..a2e69adab 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -85,8 +85,6 @@ subroutine icepack_init_snow ! if snw_aging_table = 'file' ! all data has to be passed into icepack_parameters - ! tcraig, should be 223.15 and 243.15 below - if (snwgrain) then if (trim(snw_aging_table) == 'snicar') then ! read netcdf file isnw_rhos = 8 ! maxiumum snow density index @@ -98,7 +96,7 @@ subroutine icepack_init_snow min_Tgrd = 0.0_dbl_kind del_Tgrd = 10.0_dbl_kind lin_Tgrd = .true. - min_T = 223.0_dbl_kind + min_T = 223.15_dbl_kind del_T = 5.0_dbl_kind lin_T = .true. allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) @@ -132,7 +130,7 @@ subroutine icepack_init_snow min_Tgrd = 0.0_dbl_kind del_Tgrd = 10.0_dbl_kind lin_Tgrd = .true. - min_T = 243.0_dbl_kind + min_T = 243.15_dbl_kind del_T = 5.0_dbl_kind lin_T = .true. allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T)) diff --git a/configuration/scripts/tests/base_suite.ts b/configuration/scripts/tests/base_suite.ts index 2e2bcc42d..2e074f256 100644 --- a/configuration/scripts/tests/base_suite.ts +++ b/configuration/scripts/tests/base_suite.ts @@ -16,8 +16,8 @@ smoke col 1x1 debug,run1year,leap,dt30min smoke col 1x1 debug,run1year,dyn smoke col 1x1 debug,run1year,fsd12 smoke col 1x1 debug,run1year,fsd1 -smoke col 1x1 debug,run1year,snwITDrdg,snwgrain -smoke col 1x1 debug,run1year,snw30percent +smoke col 1x1 debug,run1year,snw30percent,snwgrain +smoke col 1x1 debug,run1year,snwITDrdg restart col 1x1 debug restart col 1x1 diag1 restart col 1x1 pondcesm From 10f07f6a9db664b1be9a77a4d4a65681cbaabab9 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Tue, 29 Jun 2021 13:01:41 -0600 Subject: [PATCH 35/47] send rsnw to dEdd; limit rsnw below; fix snow SSL for z tracers --- columnphysics/icepack_itd.F90 | 16 ++++++++-------- columnphysics/icepack_shortwave.F90 | 3 ++- columnphysics/icepack_therm_itd.F90 | 4 ++-- configuration/driver/icedrv_init_column.F90 | 5 ++++- configuration/driver/icedrv_step.F90 | 5 ++++- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/columnphysics/icepack_itd.F90 b/columnphysics/icepack_itd.F90 index 4b9ef197d..5757b7bb3 100644 --- a/columnphysics/icepack_itd.F90 +++ b/columnphysics/icepack_itd.F90 @@ -1424,14 +1424,14 @@ subroutine zap_snow(dt, nslyr, & endif ! tr_iso if (z_tracers) then - dvssl = min(p5*vsnon, hs_ssl*aicen) !snow surface layer - dvint = vsnon- dvssl !snow interior - - do it = 1, nbtrcr - xtmp = (trcrn(bio_index(it)+nblyr+1)*dvssl + & - trcrn(bio_index(it)+nblyr+2)*dvint)/dt - dflux_bio(it) = dflux_bio(it) + xtmp - enddo ! it + dvssl = min(p5*vsnon/real(nslyr,kind=dbl_kind), hs_ssl*aicen) ! snow surface layer + dvint = vsnon - dvssl ! snow interior + + do it = 1, nbtrcr + xtmp = (trcrn(bio_index(it)+nblyr+1)*dvssl + & + trcrn(bio_index(it)+nblyr+2)*dvint)/dt + dflux_bio(it) = dflux_bio(it) + xtmp + enddo ! it endif ! z_tracers diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 7f3088e7e..1f25e9dc7 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -44,7 +44,7 @@ module icepack_shortwave use icepack_parameters, only: c0, c1, c1p5, c2, c3, c4, c10 use icepack_parameters, only: p01, p1, p15, p25, p5, p75, puny use icepack_parameters, only: albocn, Timelt, snowpatch, awtvdr, awtidr, awtvdf, awtidf - use icepack_parameters, only: kappav, hs_min, rhofresh, rhos, nspint, rsnw_fall, snwredist + use icepack_parameters, only: kappav, hs_min, rhofresh, rhos, nspint, rsnw_fall, snwredist, rsnw_tmax use icepack_parameters, only: hi_ssl, hs_ssl, min_bgc, sk_l, snwlvlfac, snwgrain use icepack_parameters, only: z_tracers, skl_bgc, calc_tsfc, shortwave, kalg, heat_capacity use icepack_parameters, only: r_ice, r_pnd, r_snw, dt_mlt, rsnw_mlt, hs0, hs1, hp1 @@ -3670,6 +3670,7 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & do ks = 1, nslyr rsnw(ks) = max(rsnw_fall,rsnow(ks)) + rsnw(ks) = min(rsnw_tmax,rsnow(ks)) rhosnw(ks) = rhos enddo diff --git a/columnphysics/icepack_therm_itd.F90 b/columnphysics/icepack_therm_itd.F90 index 6a61ea011..4af3848dd 100644 --- a/columnphysics/icepack_therm_itd.F90 +++ b/columnphysics/icepack_therm_itd.F90 @@ -1212,8 +1212,8 @@ subroutine lateral_melt (dt, ncat, & !----------------------------------------------------------------- if (z_tracers) then ! snow tracers - dvssl = min(p5*vsnon(n), hs_ssl*aicen(n)) !snow surface layer - dvint = vsnon(n)- dvssl !snow interior + dvssl = min(p5*vsnon(n)/real(nslyr,kind=dbl_kind), hs_ssl*aicen(n)) ! snow surface layer + dvint = vsnon(n) - dvssl ! snow interior do k = 1, nbtrcr flux_bio(k) = flux_bio(k) & + (trcrn(bio_index(k)+nblyr+1,n)*dvssl & diff --git a/configuration/driver/icedrv_init_column.F90 b/configuration/driver/icedrv_init_column.F90 index d8deade79..0068ae021 100644 --- a/configuration/driver/icedrv_init_column.F90 +++ b/configuration/driver/icedrv_init_column.F90 @@ -136,7 +136,7 @@ subroutine init_shortwave logical (kind=log_kind) :: tr_brine, tr_zaero, tr_bgc_N integer (kind=int_kind) :: nt_alvl, nt_apnd, nt_hpnd, nt_ipnd, nt_aero, & - nt_fbri, nt_tsfc, ntrcr, nbtrcr_sw, nlt_chl_sw + nt_fbri, nt_tsfc, nt_rsnw, ntrcr, nbtrcr_sw, nlt_chl_sw integer (kind=int_kind), dimension(icepack_max_aero) :: nlt_zaero_sw integer (kind=int_kind), dimension(icepack_max_aero) :: nt_zaero integer (kind=int_kind), dimension(icepack_max_algae) :: nt_bgc_N @@ -160,6 +160,7 @@ subroutine init_shortwave nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, & nt_ipnd_out=nt_ipnd, nt_aero_out=nt_aero, & nt_fbri_out=nt_fbri, nt_tsfc_out=nt_tsfc, & + nt_rsnw_out=nt_rsnw, & nt_bgc_N_out=nt_bgc_N, nt_zaero_out=nt_zaero, & nlt_chl_sw_out=nlt_chl_sw, nlt_zaero_sw_out=nlt_zaero_sw) call icepack_warnings_flush(nu_diag) @@ -276,6 +277,8 @@ subroutine init_shortwave albpndn=albpndn(i,:), apeffn=apeffn(i,:), & snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & + rsnow=trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & +!history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point, & initonly = .true.) endif diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 7c105e43e..19a6bf7b2 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -952,7 +952,7 @@ subroutine step_radiation (dt) integer (kind=int_kind) :: & max_aero, max_algae, nt_Tsfc, nt_alvl, & nt_apnd, nt_hpnd, nt_ipnd, nt_aero, nlt_chl_sw, & - ntrcr, nbtrcr_sw, nt_fbri + ntrcr, nbtrcr_sw, nt_fbri, nt_rsnw integer (kind=int_kind), dimension(:), allocatable :: & nlt_zaero_sw, nt_zaero, nt_bgc_N @@ -999,6 +999,7 @@ subroutine step_radiation (dt) nt_Tsfc_out=nt_Tsfc, nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd, & nt_hpnd_out=nt_hpnd, nt_ipnd_out=nt_ipnd, nt_aero_out=nt_aero, & nlt_chl_sw_out=nlt_chl_sw, nlt_zaero_sw_out=nlt_zaero_sw, & + nt_rsnw_out=nt_rsnw, & nt_fbri_out=nt_fbri, nt_zaero_out=nt_zaero, nt_bgc_N_out=nt_bgc_N) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -1066,6 +1067,8 @@ subroutine step_radiation (dt) albpndn=albpndn(i,:), apeffn=apeffn(i,:), & snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & + rsnow=trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & +!history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point) endif ! tmask From 82eddc3b6d8437ee6ae0ccd09a63d39ec7c1564b Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Tue, 29 Jun 2021 16:22:39 -0600 Subject: [PATCH 36/47] updating snow options in icepack for consistency with cice --- configuration/scripts/icepack_in | 6 +++--- configuration/scripts/options/set_env.snw30percent | 2 +- configuration/scripts/options/set_env.snwITDrdg | 2 +- configuration/scripts/options/set_env.snwgrain | 2 +- configuration/scripts/options/set_nml.snwgrain | 2 ++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 2f566d41b..df71e749f 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -80,9 +80,9 @@ / &snow_nml - snwredist = 'ITDrdg' - snwgrain = .true. - use_smliq_pnd = .true. + snwredist = 'none' + snwgrain = .false. + use_smliq_pnd = .false. rsnw_fall = 54.526 rsnw_tmax = 1500.0 rhosnew = 100.0 diff --git a/configuration/scripts/options/set_env.snw30percent b/configuration/scripts/options/set_env.snw30percent index 2cb1d34ab..c84089602 100644 --- a/configuration/scripts/options/set_env.snw30percent +++ b/configuration/scripts/options/set_env.snw30percent @@ -1,4 +1,4 @@ -setenv NSNWLYR 3 # number of vertical layers in the snow +setenv NSNWLYR 5 # number of vertical layers in the snow setenv TRSNOW 1 # set to 1 for advanced snow physics tracers diff --git a/configuration/scripts/options/set_env.snwITDrdg b/configuration/scripts/options/set_env.snwITDrdg index 1937bbdb5..5c9a34b8a 100644 --- a/configuration/scripts/options/set_env.snwITDrdg +++ b/configuration/scripts/options/set_env.snwITDrdg @@ -1,3 +1,3 @@ -setenv NSNWLYR 3 # number of vertical layers in the snow +setenv NSNWLYR 5 # number of vertical layers in the snow setenv TRSNOW 1 # set to 1 for advanced snow physics tracers diff --git a/configuration/scripts/options/set_env.snwgrain b/configuration/scripts/options/set_env.snwgrain index 1937bbdb5..5c9a34b8a 100644 --- a/configuration/scripts/options/set_env.snwgrain +++ b/configuration/scripts/options/set_env.snwgrain @@ -1,3 +1,3 @@ -setenv NSNWLYR 3 # number of vertical layers in the snow +setenv NSNWLYR 5 # number of vertical layers in the snow setenv TRSNOW 1 # set to 1 for advanced snow physics tracers diff --git a/configuration/scripts/options/set_nml.snwgrain b/configuration/scripts/options/set_nml.snwgrain index 4928dc178..ebbab032b 100644 --- a/configuration/scripts/options/set_nml.snwgrain +++ b/configuration/scripts/options/set_nml.snwgrain @@ -1,2 +1,4 @@ tr_snow = .true. snwgrain = .true. +use_smliq_pnd = .true. + From 4c4f77f07c1842c2a8eb8393690329cdb81d8709 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 1 Jul 2021 19:47:23 -0600 Subject: [PATCH 37/47] reformulate ice-liquid tracer conversions in snow; limit use of rsnow in dEdd with snwgrain; correct rhos_effn; clean up --- columnphysics/icepack_shortwave.F90 | 2 +- columnphysics/icepack_snow.F90 | 52 ++++---- columnphysics/icepack_therm_vertical.F90 | 150 +++++++++++++---------- configuration/driver/icedrv_step.F90 | 2 + 4 files changed, 115 insertions(+), 91 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 1f25e9dc7..a36e59fab 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -4220,7 +4220,7 @@ subroutine icepack_step_radiation (dt, ncat, & allocate(l_rsnow (nslyr,ncat)) l_rsnow = c0 - if (present(rsnow)) l_rsnow = rsnow + if (snwgrain .and. present(rsnow)) l_rsnow = rsnow allocate(l_rsnw_dEddn (ncat)) l_rsnw_dEddn = c0 diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index a2e69adab..d9217e199 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -240,8 +240,8 @@ subroutine icepack_step_snow(dt, nilyr, & real (kind=dbl_kind), dimension(:,:), intent(inout) :: & zqsn , & ! snow enthalpy (J/m^3) - smice , & ! mass of ice in snow (kg/m^3) - smliq , & ! mass of liquid in snow (kg/m^3) + smice , & ! tracer for mass of ice in snow (kg/m^3) + smliq , & ! tracer for mass of liquid in snow (kg/m^3) rsnw , & ! snow grain radius (10^-6 m) rhos_effn, & ! effective snow density: content (kg/m^3) rhos_cmpn ! effective snow density: compaction (kg/m^3) @@ -363,8 +363,8 @@ subroutine snow_effective_density(nslyr, ncat, & real (kind=dbl_kind), dimension(:,:), & intent(inout) :: & - smice , & ! mass of ice in snow (kg/m^3) - smliq , & ! mass of liquid in snow (kg/m^3) + smice , & ! tracer for mass of ice in snow (kg/m^3) + smliq , & ! tracer for mass of liquid in snow (kg/m^3) rhos_effn, & ! effective snow density: content (kg/m^3) rhos_cmpn ! effective snow density: compaction (kg/m^3) @@ -405,7 +405,7 @@ subroutine snow_effective_density(nslyr, ncat, & do n = 1, ncat if (vsnon(n) > c0) then do k = 1, nslyr - rhos_effn(k,n) = rhos_effn(k,n) + smice(k,n) + smliq(k,n) + rhos_effn(k,n) = smice(k,n) + smliq(k,n) rhos_eff = rhos_eff + vsnon(n)*rhos_effn(k,n) rhos_cmp = rhos_cmp + vsnon(n)*rhos_cmpn(k,n) enddo @@ -872,36 +872,36 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & Tsfc, zTin, hsn, zqsn, smice, smliq) integer (kind=int_kind), intent(in) :: & - ncat, & ! number of categories - nslyr, & ! number of snow layers - nilyr ! number of ice layers + ncat , & ! number of categories + nslyr , & ! number of snow layers + nilyr ! number of ice layers real (kind=dbl_kind), intent(in) :: & - dt ! time step + dt ! time step real (kind=dbl_kind), dimension(ncat), intent(in) :: & - zTin , & ! surface ice temperature (oC) - Tsfc , & ! surface temperature (oC) - hin , & ! ice thickness (m) - hsn ! snow thickness (m) + zTin , & ! surface ice temperature (oC) + Tsfc , & ! surface temperature (oC) + hin , & ! ice thickness (m) + hsn ! snow thickness (m) real (kind=dbl_kind), dimension(nslyr,ncat), intent(in) :: & - zqsn ! enthalpy of snow (J m-3) + zqsn ! enthalpy of snow (J m-3) real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: & - rsnw ! snow grain radius + rsnw ! snow grain radius real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: & - smice, & ! mass of ice in snow (kg/m^2) - smliq ! mass of liquid in snow (kg/m^2) + smice , & ! tracer for mass of ice in snow (kg/m^3) + smliq ! tracer for mass of liquid in snow (kg/m^3) ! local temporary variables integer (kind=int_kind) :: k, n real (kind=dbl_kind), dimension(nslyr) :: & - drsnw_wet, & ! wet metamorphism (10^-6 m) - drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m) + drsnw_wet, & ! wet metamorphism (10^-6 m) + drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m) character (len=*),parameter :: subname='(update_snow_radius)' @@ -972,8 +972,8 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & real (kind=dbl_kind), dimension(nslyr), & intent(in) :: & - smice , & ! mass of ice in snow (kg/m^3) - smliq , & ! mass of liquid in snow (kg/m^3) + smice , & ! tracer for mass of ice in snow (kg/m^3) + smliq , & ! tracer for mass of liquid in snow (kg/m^3) rsnw, & ! snow grain radius (10^-6 m) zqsn ! snow enthalpy (J m-3) @@ -1243,11 +1243,11 @@ subroutine drain_snow (dt, nslyr, vsnon, aicen, & real (kind=dbl_kind), dimension(nslyr), & intent(in) :: & - smice ! mass of ice in snow (kg/m^2) + smice ! tracer for mass of ice in snow (kg/m^3) real (kind=dbl_kind), dimension(nslyr), & intent(inout) :: & - smliq ! mass of liquid in snow (kg/m^2) + smliq ! tracer for mass of liquid in snow (kg/m^3) ! local temporary variables @@ -1274,12 +1274,12 @@ subroutine drain_snow (dt, nslyr, vsnon, aicen, & hslyr = hsn / real(nslyr,kind=dbl_kind) meltsliq = c0 do k = 1,nslyr - smliq(k) = smliq(k) + dlin(k) / hslyr ! liquid in from above layer + smliq(k) = smliq(k) + dlin(k) / hslyr ! liquid in from layer above phi_ice(k) = min(c1, smice(k) / rhoi) - phi_liq(k) = smliq(k)/rhofresh + phi_liq(k) = smliq(k) / rhofresh w_drain(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) / dt * rhofresh * hslyr) dlout(k) = w_drain(k) * dt - smliq(k) = smliq(k) - dlout(k)/ hslyr + smliq(k) = smliq(k) - dlout(k) / hslyr if (k < nslyr) then dlin(k+1) = dlout(k) else diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index ceca17420..cd669c3be 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -1134,8 +1134,7 @@ subroutine thickness_changes (nilyr, nslyr, & wk1 , & ! temporary variable zqsnew , & ! enthalpy of new snow (J m-3) hstot , & ! snow thickness including new snow (m) - Tmlts , & ! melting temperature - smice_fsnow ! ice mass added to snow (kg/m^2) + Tmlts ! melting temperature real (kind=dbl_kind), dimension (nilyr+1) :: & zi1 , & ! depth of ice layer boundaries (m) @@ -1151,7 +1150,9 @@ subroutine thickness_changes (nilyr, nslyr, & real (kind=dbl_kind), dimension (nslyr) :: & dzs , & ! snow layer thickness after growth/melting smicetot , & ! total ice mass of snow in each layer (kg/m^2) - smliqtot ! total liquid mass of snow in each layer (kg/m^2) + smliqtot , & ! total liquid mass of snow in each layer (kg/m^2) + dsmicetot , & ! change in smicetot (kg/m^2) + dsmliqtot ! change in smliqtot (kg/m^2) real (kind=dbl_kind), dimension (nilyr) :: & qm , & ! energy of melting (J m-3) = zqin in BL99 formulation @@ -1178,9 +1179,11 @@ subroutine thickness_changes (nilyr, nslyr, & enddo do k = 1, nslyr - dzs(k) = hslyr - smicetot(k) = dzs(k) * smice(k) - smliqtot(k) = dzs(k) * smliq(k) + dzs (k) = hslyr + smicetot (k) = dzs(k) * smice(k) + smliqtot (k) = dzs(k) * smliq(k) + dsmicetot(k) = c0 + dsmliqtot(k) = c0 enddo do k = 1, nilyr @@ -1206,12 +1209,11 @@ subroutine thickness_changes (nilyr, nslyr, & Ts = (Lfresh + zqsn(k)/rhos) / cp_ice if (Ts > c0) then dhs = cp_ice*Ts*dzs(k) / Lfresh - smice_fsnow = c0 - if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs - smicetot(k) = smicetot(k) - smice_fsnow ! dhs << dzs - smliqtot(k) = smliqtot(k) + smice_fsnow - dzs(k) = dzs(k) - dhs + dzs(k) = dzs(k) - dhs ! dhs > 0 + melts = melts + dhs zqsn(k) = -rhos*Lfresh + dsmicetot(k) = dsmicetot(k) - smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) + smice(k) * dhs endif enddo @@ -1258,7 +1260,7 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(1) = dzs(1) + dhs evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos - smicetot(1) = dhs*rhos + smicetot(1) ! new snow ice + dsmicetot(1) = dhs*rhos + dsmicetot(1) ! new snow ice else ! add ice with enthalpy zqin(1) dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 dzi(1) = dzi(1) + dhi @@ -1336,19 +1338,20 @@ subroutine thickness_changes (nilyr, nslyr, & ! Remove internal snow melt !-------------------------------------------------------------- - if (ktherm == 2 .and. zqsn(k) > -rhos * Lfresh) then +! more efficient formulation using Ts, dhs > 0 (not BFB) +! Ts = (Lfresh + zqsn(k)/rhos) / cp_ice +! if (ktherm == 2 .and. Ts > c0) then +! dhs = -dzs(k) * cp_ice*Ts/Lfresh ! dhs < 0 + if (ktherm == 2 .and. zqsn(k) > -rhos * Lfresh) then dhs = max(-dzs(k), & -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k)) - smice_fsnow = c0 - if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs - smicetot(k) = smicetot(k) + smice_fsnow ! -dhs <= dzs - smliqtot(k) = smliqtot(k) - smice_fsnow - dzs(k) = dzs(k) + dhs + dzs(k) = dzs(k) + dhs ! dhs < 0 zqsn(k) = -rhos * Lfresh melts = melts - dhs + dsmicetot(k) = dsmicetot(k) + smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs ! delta E = zqsn(k) + rhos * Lfresh - endif !-------------------------------------------------------------- @@ -1357,31 +1360,24 @@ subroutine thickness_changes (nilyr, nslyr, & qsub = zqsn(k) - rhos*Lvap ! qsub < 0 dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 - - smice_fsnow = c0 - if (abs(dzs(k)) > puny) smice_fsnow = dhs * smicetot(k)/dzs(k) - smicetot(k) = smicetot(k) + smice_fsnow - dzs(k) = dzs(k) + dhs esub = esub - dhs*qsub esub = max(esub, c0) ! in case of roundoff error - evapn = evapn + dhs*rhos + evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos + dsmicetot(k) = dsmicetot(k) + smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs !-------------------------------------------------------------- ! Melt snow (top) !-------------------------------------------------------------- dhs = max(-dzs(k), etop_mlt/zqsn(k)) - - smice_fsnow = c0 - if (abs(dzs(k)) > puny) smice_fsnow = smicetot(k)/dzs(k) * dhs - smicetot(k) = smicetot(k) + smice_fsnow - smliqtot(k) = smliqtot(k) - smice_fsnow - dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 etop_mlt = etop_mlt - dhs*zqsn(k) etop_mlt = max(etop_mlt, c0) ! in case of roundoff error + dsmicetot(k) = dsmicetot(k) + smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs ! history diagnostics if (dhs < -puny .and. mlt_onset < puny) & @@ -1459,9 +1455,9 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 ebot_mlt = ebot_mlt - dhs*zqsn(k) ebot_mlt = max(ebot_mlt, c0) - - ! Add this to the snow melt (J. Zhu) melts = melts - dhs + dsmicetot(k) = dsmicetot(k) + smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs enddo ! nslyr @@ -1497,7 +1493,7 @@ subroutine thickness_changes (nilyr, nslyr, & if (tr_snow) then !echmod - is tr_snow needed? ! ice mass in snow due to snowfall ! new snow density = rhos for now !echmod - fix this - smicetot(1) = smicetot(1) + hsn_new * rhos ! kg/m^2 + dsmicetot(1) = dsmicetot(1) + hsn_new * rhos ! kg/m^2 endif dzs(1) = hstot endif @@ -1507,7 +1503,7 @@ subroutine thickness_changes (nilyr, nslyr, & !---! Add rain at top surface (only to liquid tracer) !---!----------------------------------------------------------------- - smliqtot(1) = smliqtot(1) + frain*dt + dsmliqtot(1) = dsmliqtot(1) + frain*dt !----------------------------------------------------------------- ! Find the new ice and snow thicknesses. @@ -1522,7 +1518,7 @@ subroutine thickness_changes (nilyr, nslyr, & do k = 1, nslyr hsn = hsn + dzs(k) - dsnow = dsnow + dzs(k) - hslyr + dsnow = dsnow + dzs(k) - hslyr enddo ! k !------------------------------------------------------------------- @@ -1530,7 +1526,7 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- if (snwgrain .and. hsn_new > c0) then - tmp1 = max(c0, dzs(1) - hsn_new) + tmp1 = max(c0, dzs(1) - hsn_new) rsnw(1) = (rsnw_fall * hsn_new + rsnw(1) * tmp1) & / max( hsn_new + tmp1, puny) rsnw(1) = max(rsnw_fall, min(rsnw_tmax, rsnw(1))) @@ -1541,31 +1537,55 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- if (ktherm /= 2) & - call freeboard (nslyr, & - snoice, & - hin, hsn, & - zqin, zqsn, & - dzi, dzs, & - dsnow, & - smicetot(:), & - smliqtot(:)) + call freeboard (nslyr, snoice, & + hin, hsn, & + zqin, zqsn, & + dzi, dzs, & + dsnow, & + smice(:), dsmicetot(:), & + smliq(:), dsmliqtot(:)) if (icepack_warnings_aborted(subname)) return !------------------------------------------------------------------- ! Update snow mass tracers, smice and smliq, for uneven layers !------------------------------------------------------------------- - if (snwgrain) then + + if (snwgrain) then do k = 1, nslyr - meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) + smicetot(k) = smicetot(k) + dsmicetot(k) + smliqtot(k) = smliqtot(k) + dsmliqtot(k) + meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) if (dzs(k) > c0) then smice(k) = smicetot(k) / dzs(k) smliq(k) = smliqtot(k) / dzs(k) else + smicetot(k) = c0 + smliqtot(k) = c0 smice(k) = c0 smliq(k) = c0 endif enddo - endif + + !------------------------------------------------------------------- + ! Check for negative snow mass tracers + !------------------------------------------------------------------- + + do k = 1, nslyr + if (smicetot(k) < c0) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" Snow: ice mass tracer error" ) + write(warnstr,*) subname, ' negative smicetot' + call icepack_warnings_add(warnstr) + endif + if (smliqtot(k) < c0) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" Snow: liquid mass tracer error" ) + write(warnstr,*) subname, ' negative smliqtot' + call icepack_warnings_add(warnstr) + endif + enddo + + endif ! snwgrain !---!------------------------------------------------------------------- !---! Repartition the ice and snow into equal-thickness layers, @@ -1740,8 +1760,9 @@ subroutine freeboard (nslyr, & hin, hsn, & zqin, zqsn, & dzi, dzs, & - dsnow, smicetot, & - smliqtot) + dsnow, & + smice, dsmicetot,& + smliq, dsmliqtot) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -1761,14 +1782,16 @@ subroutine freeboard (nslyr, & hsn ! snow thickness (m) real (kind=dbl_kind), dimension (:), intent(in) :: & - zqsn ! snow layer enthalpy (J m-3) + zqsn , & ! snow layer enthalpy (J m-3) + smice , & ! tracer for ice mass in snow layer (kg/m^3) + smliq ! tracer for liquid mass in snow layer (kg/m^3) real (kind=dbl_kind), dimension (:), intent(inout) :: & - zqin , & ! ice layer enthalpy (J m-3) - dzi , & ! ice layer thicknesses (m) - dzs , & ! snow layer thicknesses (m) - smicetot, & ! snow ice mass per layer (kg/m^2) - smliqtot ! snow liquid mass per layer (kg/m^2) + zqin , & ! ice layer enthalpy (J m-3) + dzi , & ! ice layer thicknesses (m) + dzs , & ! snow layer thicknesses (m) + dsmicetot, & ! change in snow ice mass per layer (kg/m^2) + dsmliqtot ! change in snow liquid mass per layer (kg/m^2) ! local variables @@ -1811,14 +1834,13 @@ subroutine freeboard (nslyr, & dhs = min(dhsn, dzs(k)) ! snow to remove from layer hsn = hsn - dhs dsnow = dsnow - dhs ! new snow - - smicetot(k) = smicetot(k) - dhs * smicetot(k) / dzs(k) - smliqtot(k) = smliqtot(k) - dhs * smliqtot(k) / dzs(k) - dzs(k) = dzs(k) - dhs dhsn = dhsn - dhs dhsn = max(dhsn,c0) hqs = hqs + dhs * zqsn(k) + ! remove both ice and liquid from snow to add to ice + dsmicetot(k) = dsmicetot(k) - smice(k) * dhs + dsmliqtot(k) = dsmliqtot(k) - smliq(k) * dhs endif ! dhin > puny enddo @@ -2241,8 +2263,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & real (kind=dbl_kind), dimension(:,:), optional, intent(inout) :: & rsnwn , & ! snow grain radius (10^-6 m) - smicen , & ! mass of ice in snow (kg/m^2) - smliqn ! mass of liquid in snow (kg/m^2) + smicen , & ! tracer for mass of ice in snow (kg/m^3) + smliqn ! tracer for mass of liquid in snow (kg/m^3) real (kind=dbl_kind), optional, intent(in) :: & HDO_ocn , & ! ocean concentration of HDO (kg/kg) @@ -2357,8 +2379,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & real (kind=dbl_kind), allocatable, dimension(:,:) :: & l_rsnw , & ! snow grain radius (10^-6 m) - l_smice , & ! mass of ice in snow (kg/m^2) - l_smliq ! mass of liquid in snow (kg/m^2) + l_smice , & ! tracer for mass of ice in snow (kg/m^3) + l_smliq ! tracer for mass of liquid in snow (kg/m^3) real (kind=dbl_kind) :: & l_fsloss , & ! fraction of snow lost to leads diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 19a6bf7b2..94e69075e 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -892,6 +892,8 @@ subroutine step_snow (dt) do i = 1, nx + ! the effective snow density is not currently used outside of + ! the snow model, but is made available here for future use rhos_effn(:,:) = c0 call icepack_step_snow (dt, nilyr, & From f9ac9d002ec1f274a51f0b6e8dcdb9fbb4dfe5cd Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 8 Jul 2021 07:13:07 -0600 Subject: [PATCH 38/47] another approach for ice/liquid tracer conversions in snow --- columnphysics/icepack_therm_vertical.F90 | 97 +++++++++++++----------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index cd669c3be..ff8df5f11 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -1150,9 +1150,7 @@ subroutine thickness_changes (nilyr, nslyr, & real (kind=dbl_kind), dimension (nslyr) :: & dzs , & ! snow layer thickness after growth/melting smicetot , & ! total ice mass of snow in each layer (kg/m^2) - smliqtot , & ! total liquid mass of snow in each layer (kg/m^2) - dsmicetot , & ! change in smicetot (kg/m^2) - dsmliqtot ! change in smliqtot (kg/m^2) + smliqtot ! total liquid mass of snow in each layer (kg/m^2) real (kind=dbl_kind), dimension (nilyr) :: & qm , & ! energy of melting (J m-3) = zqin in BL99 formulation @@ -1162,6 +1160,7 @@ subroutine thickness_changes (nilyr, nslyr, & qbotm , & qbotp , & qbot0 , & + mass , & tmp1 ! temporary scalar character(len=*),parameter :: subname='(thickness_changes)' @@ -1182,8 +1181,6 @@ subroutine thickness_changes (nilyr, nslyr, & dzs (k) = hslyr smicetot (k) = dzs(k) * smice(k) smliqtot (k) = dzs(k) * smliq(k) - dsmicetot(k) = c0 - dsmliqtot(k) = c0 enddo do k = 1, nilyr @@ -1212,8 +1209,9 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(k) = dzs(k) - dhs ! dhs > 0 melts = melts + dhs zqsn(k) = -rhos*Lfresh - dsmicetot(k) = dsmicetot(k) - smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) + smice(k) * dhs + mass = smicetot(k) + smliqtot(k) + smicetot(k) = smice(k)*dzs(k) + smliqtot(k) = mass - smicetot(k) endif enddo @@ -1260,7 +1258,7 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(1) = dzs(1) + dhs evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos - dsmicetot(1) = dhs*rhos + dsmicetot(1) ! new snow ice + smicetot(1) = smice(1)*dzs(1) ! no change to smliqtot else ! add ice with enthalpy zqin(1) dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 dzi(1) = dzi(1) + dhi @@ -1349,9 +1347,10 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(k) = dzs(k) + dhs ! dhs < 0 zqsn(k) = -rhos * Lfresh melts = melts - dhs - dsmicetot(k) = dsmicetot(k) + smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs ! delta E = zqsn(k) + rhos * Lfresh + mass = smicetot(k) + smliqtot(k) + smicetot(k) = smice(k)*dzs(k) + smliqtot(k) = mass - smicetot(k) endif !-------------------------------------------------------------- @@ -1365,8 +1364,8 @@ subroutine thickness_changes (nilyr, nslyr, & esub = max(esub, c0) ! in case of roundoff error evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos - dsmicetot(k) = dsmicetot(k) + smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs + smicetot(k) = smice(k)*dzs(k) ! assume both ice and + smliqtot(k) = smliq(k)*dzs(k) ! liquid sublimate !-------------------------------------------------------------- ! Melt snow (top) @@ -1376,8 +1375,9 @@ subroutine thickness_changes (nilyr, nslyr, & dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 etop_mlt = etop_mlt - dhs*zqsn(k) etop_mlt = max(etop_mlt, c0) ! in case of roundoff error - dsmicetot(k) = dsmicetot(k) + smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs + mass = smicetot(k) + smliqtot(k) + smicetot(k) = smice(k)*dzs(k) + smliqtot(k) = mass - smicetot(k) ! history diagnostics if (dhs < -puny .and. mlt_onset < puny) & @@ -1456,8 +1456,9 @@ subroutine thickness_changes (nilyr, nslyr, & ebot_mlt = ebot_mlt - dhs*zqsn(k) ebot_mlt = max(ebot_mlt, c0) melts = melts - dhs - dsmicetot(k) = dsmicetot(k) + smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) - smice(k) * dhs + mass = smicetot(k) + smliqtot(k) + smicetot(k) = smice(k)*dzs(k) + smliqtot(k) = mass - smicetot(k) enddo ! nslyr @@ -1489,13 +1490,8 @@ subroutine thickness_changes (nilyr, nslyr, & zqsn(1) = (dzs(1) * zqsn(1) & + hsn_new * zqsnew) / hstot zqsn(1) = min(zqsn(1), zqsnew) ! avoid roundoff errors - - if (tr_snow) then !echmod - is tr_snow needed? - ! ice mass in snow due to snowfall - ! new snow density = rhos for now !echmod - fix this - dsmicetot(1) = dsmicetot(1) + hsn_new * rhos ! kg/m^2 - endif dzs(1) = hstot + smicetot(1) = smice(1)*dzs(1) ! no change to smliqtot endif endif @@ -1503,7 +1499,7 @@ subroutine thickness_changes (nilyr, nslyr, & !---! Add rain at top surface (only to liquid tracer) !---!----------------------------------------------------------------- - dsmliqtot(1) = dsmliqtot(1) + frain*dt + smliqtot(1) = smliqtot(1) + frain*dt !----------------------------------------------------------------- ! Find the new ice and snow thicknesses. @@ -1542,8 +1538,8 @@ subroutine thickness_changes (nilyr, nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice(:), dsmicetot(:), & - smliq(:), dsmliqtot(:)) + smice, smliq, & + smicetot, smliqtot) if (icepack_warnings_aborted(subname)) return !------------------------------------------------------------------- @@ -1551,9 +1547,8 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- if (snwgrain) then + do k = 1, nslyr - smicetot(k) = smicetot(k) + dsmicetot(k) - smliqtot(k) = smliqtot(k) + dsmliqtot(k) meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) if (dzs(k) > c0) then smice(k) = smicetot(k) / dzs(k) @@ -1571,17 +1566,31 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- do k = 1, nslyr - if (smicetot(k) < c0) then - call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - call icepack_warnings_add(subname//" Snow: ice mass tracer error" ) - write(warnstr,*) subname, ' negative smicetot' - call icepack_warnings_add(warnstr) + if (smicetot(k) < -puny) then + if (smicetot(k) > -puny) then + smicetot(k) = c0 + smice(k) = c0 + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" Snow: ice mass tracer error" ) + write(warnstr,*) subname, ' negative smicetot', k,smicetot(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, ' dzs, smice', k,dzs(k), smice(k) + call icepack_warnings_add(warnstr) + endif endif if (smliqtot(k) < c0) then - call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - call icepack_warnings_add(subname//" Snow: liquid mass tracer error" ) - write(warnstr,*) subname, ' negative smliqtot' - call icepack_warnings_add(warnstr) + if (smliqtot(k) > -puny) then + smliqtot(k) = c0 + smliq(k) = c0 + else + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" Snow: liquid mass tracer error" ) + write(warnstr,*) subname, ' negative smliqtot', k,smliqtot(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, ' dzs, smliq', k,dzs(k), smliq(k) + call icepack_warnings_add(warnstr) + endif endif enddo @@ -1761,8 +1770,8 @@ subroutine freeboard (nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice, dsmicetot,& - smliq, dsmliqtot) + smice, smliq, & + smicetot, smliqtot) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -1783,15 +1792,15 @@ subroutine freeboard (nslyr, & real (kind=dbl_kind), dimension (:), intent(in) :: & zqsn , & ! snow layer enthalpy (J m-3) - smice , & ! tracer for ice mass in snow layer (kg/m^3) - smliq ! tracer for liquid mass in snow layer (kg/m^3) + smice , & ! liquid water mass tracer in snow (kg/m^3) + smliq ! ice mass tracer in snow (kg/m^3) real (kind=dbl_kind), dimension (:), intent(inout) :: & zqin , & ! ice layer enthalpy (J m-3) dzi , & ! ice layer thicknesses (m) dzs , & ! snow layer thicknesses (m) - dsmicetot, & ! change in snow ice mass per layer (kg/m^2) - dsmliqtot ! change in snow liquid mass per layer (kg/m^2) + smicetot , & ! total ice mass of snow in each layer (kg/m^2) + smliqtot ! total liquid mass of snow in each layer (kg/m^2) ! local variables @@ -1839,8 +1848,8 @@ subroutine freeboard (nslyr, & dhsn = max(dhsn,c0) hqs = hqs + dhs * zqsn(k) ! remove both ice and liquid from snow to add to ice - dsmicetot(k) = dsmicetot(k) - smice(k) * dhs - dsmliqtot(k) = dsmliqtot(k) - smliq(k) * dhs + smicetot(k) = smice(k)*dzs(k) + smliqtot(k) = smliq(k)*dzs(k) endif ! dhin > puny enddo From fe2192bfe1b5c260f7793203cd76ef22755dfd21 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Wed, 28 Jul 2021 12:14:35 -0600 Subject: [PATCH 39/47] enforce mass conservation of snow ice and liquid tracers, to maintain consistency with rhos based snow volume transport --- columnphysics/icepack_snow.F90 | 51 ++-- columnphysics/icepack_therm_vertical.F90 | 291 ++++++++++++++++------- 2 files changed, 220 insertions(+), 122 deletions(-) diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index d9217e199..7708eb8f4 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -917,8 +917,7 @@ subroutine update_snow_radius (dt, ncat, nslyr, nilyr, rsnw, hin, & !----------------------------------------------------------------- call snow_dry_metamorph (nslyr, nilyr, dt, rsnw(:,n), & drsnw_dry, zqsn(:,n), Tsfc(n), & - zTin(n), hsn(n), hin(n), & - smice(:,n), smliq(:,n)) + zTin(n), hsn(n), hin(n)) if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- @@ -948,7 +947,7 @@ end subroutine update_snow_radius ! Snow grain metamorphism subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & - Tsfc, zTin1, hsn, hin, smice, smliq) + Tsfc, zTin1, hsn, hin) ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that ! depend on snow temperature, temperature gradient, and density, @@ -972,8 +971,6 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & real (kind=dbl_kind), dimension(nslyr), & intent(in) :: & - smice , & ! tracer for mass of ice in snow (kg/m^3) - smliq , & ! tracer for mass of liquid in snow (kg/m^3) rsnw, & ! snow grain radius (10^-6 m) zqsn ! snow enthalpy (J m-3) @@ -997,7 +994,6 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & rhos_idx ! density index real (kind=dbl_kind), dimension(nslyr):: & - zrhos, & ! snow density (kg/m^3) ! for variable snow density zdTdz, & ! temperature gradient (K/s) zTsn ! snow temperature (C) @@ -1059,7 +1055,6 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & drsnw_dry(:) = c0 zTsn(:) = c0 zdTdz(:) = c0 - zrhos(:) = rhos dzs = hsn/real(nslyr,kind=dbl_kind) dzi = hin/real(nilyr,kind=dbl_kind) @@ -1088,7 +1083,6 @@ subroutine snow_dry_metamorph (nslyr,nilyr, dt, rsnw, drsnw_dry, zqsn, & endif do k = 1, nslyr - zrhos(k) = smice(k) + smliq(k) !----------------------------------------------------------------- ! best-fit table indices: @@ -1227,27 +1221,26 @@ end subroutine snowtable_check_dimension ! Conversions between ice mass, liquid water mass in snow - subroutine drain_snow (dt, nslyr, vsnon, aicen, & - smice, smliq, meltsliq) + subroutine drain_snow (nslyr, vsnon, aicen, & + massice, massliq, meltsliq) integer (kind=int_kind), intent(in) :: & - nslyr ! number of snow layers + nslyr ! number of snow layers real (kind=dbl_kind), intent(in) :: & - dt, & ! time step vsnon, & ! snow volume (m) - aicen ! aice area + aicen ! aice area fraction real (kind=dbl_kind), intent(inout) :: & - meltsliq ! total liquid content + meltsliq ! total liquid content (kg/m^2) real (kind=dbl_kind), dimension(nslyr), & intent(in) :: & - smice ! tracer for mass of ice in snow (kg/m^3) + massice ! mass of ice in snow (kg/m^2) real (kind=dbl_kind), dimension(nslyr), & intent(inout) :: & - smliq ! tracer for mass of liquid in snow (kg/m^3) + massliq ! mass of liquid in snow (kg/m^2) ! local temporary variables @@ -1258,32 +1251,30 @@ subroutine drain_snow (dt, nslyr, vsnon, aicen, & hsn ! snow thickness (m) real (kind=dbl_kind), dimension(nslyr) :: & - dlin , & ! liquid into the layer from above (kg/m^2) - dlout , & ! liquid out of the layer (kg/m^2) + dlin , & ! liquid mass into the layer from above (kg/m^2) + dlout , & ! liquid mass out of the layer (kg/m^2) phi_liq , & ! volumetric liquid fraction - phi_ice , & ! volumetric ice fraction - w_drain ! flow between layers + phi_ice ! volumetric ice fraction - character (len=*),parameter :: subname='(drain_snow)' + character (len=*), parameter :: subname='(drain_snow)' hsn = c0 if (aicen > c0) hsn = vsnon/aicen if (hsn > puny) then - dlin(:) = c0 + dlin (:) = c0 dlout(:) = c0 hslyr = hsn / real(nslyr,kind=dbl_kind) meltsliq = c0 - do k = 1,nslyr - smliq(k) = smliq(k) + dlin(k) / hslyr ! liquid in from layer above - phi_ice(k) = min(c1, smice(k) / rhoi) - phi_liq(k) = smliq(k) / rhofresh - w_drain(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) / dt * rhofresh * hslyr) - dlout(k) = w_drain(k) * dt - smliq(k) = smliq(k) - dlout(k) / hslyr + do k = 1, nslyr + massliq(k) = massliq(k) + dlin(k) ! add liquid in from layer above + phi_ice(k) = min(c1, massice(k) / (rhoi *hslyr)) + phi_liq(k) = massliq(k) / (rhofresh*hslyr) + dlout(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) / rhofresh*hslyr) + massliq(k) = massliq(k) - dlout(k) if (k < nslyr) then dlin(k+1) = dlout(k) else - meltsliq = dlout(nslyr) + meltsliq = dlout(nslyr) ! this (re)initializes meltsliq endif enddo else diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index ff8df5f11..bcbcde37e 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -101,7 +101,8 @@ subroutine thermo_vertical (nilyr, nslyr, & fhocnn, frain, & meltt, melts, & meltb, meltsliq, & - smice, smliq, & + smice, massice, & + smliq, massliq, & congel, snoice, & mlt_onset, frz_onset, & yday, dsnow, & @@ -136,8 +137,10 @@ subroutine thermo_vertical (nilyr, nslyr, & zqin , & ! ice layer enthalpy, zqin < 0 (J m-3) zSin , & ! internal ice layer salinities rsnw , & ! snow grain radius (10^-6 m) - smice , & ! liquid water mass tracer in snow (kg/m^3) - smliq ! ice mass tracer in snow (kg/m^3) + smice , & ! ice mass tracer in snow (kg/m^3) + smliq , & ! liquid water mass tracer in snow (kg/m^3) + massice , & ! ice mass in snow (kg/m^2) + massliq ! liquid water mass in snow (kg/m^2) ! input from atmosphere real (kind=dbl_kind), & @@ -321,6 +324,12 @@ subroutine thermo_vertical (nilyr, nslyr, & smice, smliq) if (icepack_warnings_aborted(subname)) return + ! reinitialize mass in case of snow-ice formation + if (snwgrain) then + massice(:) = smice(:) * hslyr + massliq(:) = smliq(:) * hslyr + endif + else ! ktherm call temperature_changes(dt, & @@ -405,16 +414,17 @@ subroutine thermo_vertical (nilyr, nslyr, & hin, hilyr, & hsn, hslyr, & zqin, zqsn, & - smice, smliq, & + smice, massice, & + smliq, massliq, & fbot, Tbot, & flatn, fsurfn, & - fcondtopn, fcondbotn, & + fcondtopn, fcondbotn, & fsnow, hsn_new, & fhocnn, evapn, & evapsn, evapin, & meltt, melts, & - meltsliq, frain, & - meltb, & + meltsliq, frain, & + meltb, & congel, snoice, & mlt_onset, frz_onset, & zSin, sss, & @@ -479,10 +489,6 @@ subroutine thermo_vertical (nilyr, nslyr, & vicen, vsnon) if (icepack_warnings_aborted(subname)) return - !----------------------------------------------------------------- - ! Reload passive tracer array - !----------------------------------------------------------------- - end subroutine thermo_vertical !======================================================================= @@ -1026,7 +1032,8 @@ subroutine thickness_changes (nilyr, nslyr, & hin, hilyr, & hsn, hslyr, & zqin, zqsn, & - smice, smliq, & + smice, massice, & + smliq, massliq, & fbot, Tbot, & flatn, fsurfn, & fcondtopn, fcondbotn, & @@ -1066,7 +1073,9 @@ subroutine thickness_changes (nilyr, nslyr, & zqsn , & ! snow layer enthalpy (J m-3) rsnw , & ! snow grain radius (10^-6 m) smice , & ! ice mass tracer in snow (kg/m^3) - smliq ! liquid water mass tracer in snow (kg/m^3) + smliq , & ! liquid water mass tracer in snow (kg/m^3) + massice , & ! ice mass in snow (kg/m^2) + massliq ! liquid water mass in snow (kg/m^2) real (kind=dbl_kind), intent(inout) :: & hilyr , & ! ice layer thickness (m) @@ -1134,7 +1143,7 @@ subroutine thickness_changes (nilyr, nslyr, & wk1 , & ! temporary variable zqsnew , & ! enthalpy of new snow (J m-3) hstot , & ! snow thickness including new snow (m) - Tmlts ! melting temperature + Tmlts ! melting temperature (deg C) real (kind=dbl_kind), dimension (nilyr+1) :: & zi1 , & ! depth of ice layer boundaries (m) @@ -1145,12 +1154,10 @@ subroutine thickness_changes (nilyr, nslyr, & zs2 ! adjusted depths, with equal hslyr (m) real (kind=dbl_kind), dimension (nilyr) :: & - dzi ! ice layer thickness after growth/melting + dzi ! ice layer thickness after growth/melting (m) real (kind=dbl_kind), dimension (nslyr) :: & - dzs , & ! snow layer thickness after growth/melting - smicetot , & ! total ice mass of snow in each layer (kg/m^2) - smliqtot ! total liquid mass of snow in each layer (kg/m^2) + dzs ! snow layer thickness after growth/melting (m) real (kind=dbl_kind), dimension (nilyr) :: & qm , & ! energy of melting (J m-3) = zqin in BL99 formulation @@ -1160,7 +1167,8 @@ subroutine thickness_changes (nilyr, nslyr, & qbotm , & qbotp , & qbot0 , & - mass , & + mass , & ! total mass from snow density tracers (kg/m^2) + massi , & ! ice mass change factor tmp1 ! temporary scalar character(len=*),parameter :: subname='(thickness_changes)' @@ -1178,9 +1186,7 @@ subroutine thickness_changes (nilyr, nslyr, & enddo do k = 1, nslyr - dzs (k) = hslyr - smicetot (k) = dzs(k) * smice(k) - smliqtot (k) = dzs(k) * smliq(k) + dzs(k) = hslyr enddo do k = 1, nilyr @@ -1206,12 +1212,16 @@ subroutine thickness_changes (nilyr, nslyr, & Ts = (Lfresh + zqsn(k)/rhos) / cp_ice if (Ts > c0) then dhs = cp_ice*Ts*dzs(k) / Lfresh + + mass = massice(k) + massliq(k) + massi = c0 + if (dzs(k) > puny) massi = max(c0, c1 - dhs/dzs(k)) + massice(k) = massice(k) * massi + massliq(k) = mass - massice(k) ! conserve mass + dzs(k) = dzs(k) - dhs ! dhs > 0 melts = melts + dhs zqsn(k) = -rhos*Lfresh - mass = smicetot(k) + smliqtot(k) - smicetot(k) = smice(k)*dzs(k) - smliqtot(k) = mass - smicetot(k) endif enddo @@ -1255,10 +1265,16 @@ subroutine thickness_changes (nilyr, nslyr, & if (hsn > puny) then ! add snow with enthalpy zqsn(1) dhs = econ / (zqsn(1) - rhos*Lvap) ! econ < 0, dhs > 0 + + mass = massice(1) + massliq(1) + massi = c0 + if (dzs(1) > puny) massi = c1 + dhs/dzs(1) + massice(1) = massice(1) * massi + massliq(1) = max(c0, mass + rhos*dhs - massice(1)) ! conserve new total mass + dzs(1) = dzs(1) + dhs evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos - smicetot(1) = smice(1)*dzs(1) ! no change to smliqtot else ! add ice with enthalpy zqin(1) dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 dzi(1) = dzi(1) + dhi @@ -1344,13 +1360,17 @@ subroutine thickness_changes (nilyr, nslyr, & if (ktherm == 2 .and. zqsn(k) > -rhos * Lfresh) then dhs = max(-dzs(k), & -((zqsn(k) + rhos*Lfresh) / (rhos*Lfresh)) * dzs(k)) + + mass = massice(k) + massliq(k) + massi = c0 + if (dzs(k) > puny) massi = max(c0, c1 + dhs/dzs(k)) + massice(k) = massice(k) * massi + massliq(k) = mass - massice(k) ! conserve mass + dzs(k) = dzs(k) + dhs ! dhs < 0 zqsn(k) = -rhos * Lfresh melts = melts - dhs ! delta E = zqsn(k) + rhos * Lfresh - mass = smicetot(k) + smliqtot(k) - smicetot(k) = smice(k)*dzs(k) - smliqtot(k) = mass - smicetot(k) endif !-------------------------------------------------------------- @@ -1359,25 +1379,34 @@ subroutine thickness_changes (nilyr, nslyr, & qsub = zqsn(k) - rhos*Lvap ! qsub < 0 dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 + + mass = massice(1) + massliq(1) + massi = c0 + if (dzs(k) > puny) massi = c1 + dhs/dzs(k) + massice(k) = massice(k) * massi + massliq(k) = max(c0, mass + rhos*dhs - massice(k)) ! conserve new total mass + dzs(k) = dzs(k) + dhs esub = esub - dhs*qsub esub = max(esub, c0) ! in case of roundoff error evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos - smicetot(k) = smice(k)*dzs(k) ! assume both ice and - smliqtot(k) = smliq(k)*dzs(k) ! liquid sublimate !-------------------------------------------------------------- ! Melt snow (top) !-------------------------------------------------------------- dhs = max(-dzs(k), etop_mlt/zqsn(k)) + + mass = massice(k) + massliq(k) + massi = c0 + if (dzs(k) > puny) massi = max(c0, c1 + dhs/dzs(k)) + massice(k) = massice(k) * massi + massliq(k) = mass - massice(k) ! conserve mass + dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 etop_mlt = etop_mlt - dhs*zqsn(k) etop_mlt = max(etop_mlt, c0) ! in case of roundoff error - mass = smicetot(k) + smliqtot(k) - smicetot(k) = smice(k)*dzs(k) - smliqtot(k) = mass - smicetot(k) ! history diagnostics if (dhs < -puny .and. mlt_onset < puny) & @@ -1452,14 +1481,17 @@ subroutine thickness_changes (nilyr, nslyr, & !-------------------------------------------------------------- dhs = max(-dzs(k), ebot_mlt/zqsn(k)) + + mass = massice(k) + massliq(k) + massi = c0 + if (dzs(k) > puny) massi = max(c0, c1 + dhs/dzs(k)) + massice(k) = massice(k) * massi + massliq(k) = mass - massice(k) ! conserve mass + dzs(k) = dzs(k) + dhs ! zqsn < 0, dhs < 0 ebot_mlt = ebot_mlt - dhs*zqsn(k) ebot_mlt = max(ebot_mlt, c0) melts = melts - dhs - mass = smicetot(k) + smliqtot(k) - smicetot(k) = smice(k)*dzs(k) - smliqtot(k) = mass - smicetot(k) - enddo ! nslyr !----------------------------------------------------------------- @@ -1470,18 +1502,15 @@ subroutine thickness_changes (nilyr, nslyr, & fhocnn = fbot & + (esub + etop_mlt + ebot_mlt)/dt -!---!----------------------------------------------------------------- -!---! Add new snowfall at top surface. -!---!----------------------------------------------------------------- - - !---------------------------------------------------------------- + !----------------------------------------------------------------- + ! Add new snowfall at top surface + !---------------------------------------------------------------- ! NOTE: If heat flux diagnostics are to work, new snow should ! have T = 0 (i.e. q = -rhos*Lfresh) and should not be ! converted to rain. !---------------------------------------------------------------- if (fsnow > c0) then - hsn_new = fsnow/rhos * dt zqsnew = -rhos*Lfresh hstot = dzs(1) + hsn_new @@ -1491,15 +1520,15 @@ subroutine thickness_changes (nilyr, nslyr, & + hsn_new * zqsnew) / hstot zqsn(1) = min(zqsn(1), zqsnew) ! avoid roundoff errors dzs(1) = hstot - smicetot(1) = smice(1)*dzs(1) ! no change to smliqtot + massice(1) = massice(1) + fsnow*dt endif endif -!---!----------------------------------------------------------------- -!---! Add rain at top surface (only to liquid tracer) -!---!----------------------------------------------------------------- + !----------------------------------------------------------------- + ! Add rain at top surface (only to liquid tracer) + !----------------------------------------------------------------- - smliqtot(1) = smliqtot(1) + frain*dt + massliq(1) = massliq(1) + frain*dt !----------------------------------------------------------------- ! Find the new ice and snow thicknesses. @@ -1538,26 +1567,26 @@ subroutine thickness_changes (nilyr, nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice, smliq, & - smicetot, smliqtot) + smice, massice, & + smliq, massliq) if (icepack_warnings_aborted(subname)) return !------------------------------------------------------------------- - ! Update snow mass tracers, smice and smliq, for uneven layers + ! Update snow mass tracers for uneven layers !------------------------------------------------------------------- if (snwgrain) then do k = 1, nslyr - meltsliq = meltsliq + smliqtot(k) ! total liquid (in case all snow melted) - if (dzs(k) > c0) then - smice(k) = smicetot(k) / dzs(k) - smliq(k) = smliqtot(k) / dzs(k) + meltsliq = meltsliq + massliq(k) ! used in drain_snow when all snow has melted + if (dzs(k) > puny) then + smice(k) = massice(k) / dzs(k) + smliq(k) = massliq(k) / dzs(k) else - smicetot(k) = c0 - smliqtot(k) = c0 smice(k) = c0 smliq(k) = c0 + massice(k) = c0 + massliq(k) = c0 endif enddo @@ -1566,32 +1595,38 @@ subroutine thickness_changes (nilyr, nslyr, & !------------------------------------------------------------------- do k = 1, nslyr - if (smicetot(k) < -puny) then - if (smicetot(k) > -puny) then - smicetot(k) = c0 - smice(k) = c0 + if (massice(k) < c0) then + if (massice(k) > -puny) then + massice(k) = c0 else call icepack_warnings_setabort(.true.,__FILE__,__LINE__) call icepack_warnings_add(subname//" Snow: ice mass tracer error" ) - write(warnstr,*) subname, ' negative smicetot', k,smicetot(k) + write(warnstr,*) subname, ' negative massice', k,massice(k) call icepack_warnings_add(warnstr) write(warnstr,*) subname, ' dzs, smice', k,dzs(k), smice(k) call icepack_warnings_add(warnstr) endif endif - if (smliqtot(k) < c0) then - if (smliqtot(k) > -puny) then - smliqtot(k) = c0 - smliq(k) = c0 + if (massliq(k) < c0) then + if (massliq(k) > -puny) then + massliq(k) = c0 else call icepack_warnings_setabort(.true.,__FILE__,__LINE__) call icepack_warnings_add(subname//" Snow: liquid mass tracer error" ) - write(warnstr,*) subname, ' negative smliqtot', k,smliqtot(k) + write(warnstr,*) subname, ' negative massliq', k,massliq(k) call icepack_warnings_add(warnstr) write(warnstr,*) subname, ' dzs, smliq', k,dzs(k), smliq(k) call icepack_warnings_add(warnstr) endif endif + if (smice(k) > rhofresh) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname//" Snow: large density " ) + write(warnstr,*) subname, ' large massice', k,massice(k) + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, ' dzs, smice', k,dzs(k), smice(k) + call icepack_warnings_add(warnstr) + endif enddo endif ! snwgrain @@ -1693,16 +1728,27 @@ subroutine thickness_changes (nilyr, nslyr, & zs1(:), zs2(:), & hslyr, hsn, & rsnw(:)) - call adjust_enthalpy (nslyr, & - zs1(:), zs2(:), & + call adjust_enthalpy (nslyr, & ! need a routine to adjust + zs1(:), zs2(:), & ! mass instead of tracer hslyr, hsn, & smice(:)) call adjust_enthalpy (nslyr, & zs1(:), zs2(:), & hslyr, hsn, & smliq(:)) - endif - if (icepack_warnings_aborted(subname)) return + endif + if (icepack_warnings_aborted(subname)) return + + !------------------------------------------------------------------- + ! Update snow mass + !------------------------------------------------------------------- + + if (snwgrain) then + do k = 1, nslyr + massice(k) = smice(k) * hslyr + massliq(k) = smliq(k) * hslyr + enddo + endif endif ! nslyr > 1 @@ -1711,19 +1757,19 @@ subroutine thickness_changes (nilyr, nslyr, & !----------------------------------------------------------------- if (ktherm == 2) then - do k = 1, nslyr - if (hsn <= puny) then + if (hsn <= puny) then + do k = 1, nslyr fhocnn = fhocnn & + zqsn(k)*hsn/(real(nslyr,kind=dbl_kind)*dt) zqsn(k) = -rhos*Lfresh if (snwgrain) then - meltsliq = meltsliq + smicetot(k) ! add to meltponds + meltsliq = meltsliq + massice(k) ! add to meltponds smice(k) = c0 smliq(k) = c0 endif - hslyr = c0 - endif - enddo + enddo + hslyr = c0 + endif endif !----------------------------------------------------------------- @@ -1770,8 +1816,8 @@ subroutine freeboard (nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice, smliq, & - smicetot, smliqtot) + smice, massice, & + smliq, massliq) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -1799,8 +1845,8 @@ subroutine freeboard (nslyr, & zqin , & ! ice layer enthalpy (J m-3) dzi , & ! ice layer thicknesses (m) dzs , & ! snow layer thicknesses (m) - smicetot , & ! total ice mass of snow in each layer (kg/m^2) - smliqtot ! total liquid mass of snow in each layer (kg/m^2) + massice , & ! total ice mass of snow in each layer (kg/m^2) + massliq ! total liquid mass of snow in each layer (kg/m^2) ! local variables @@ -1814,7 +1860,9 @@ subroutine freeboard (nslyr, & real (kind=dbl_kind) :: & wk1 , & ! temporary variable - dhs ! snow to remove from layer (m) + dhs , & ! snow to remove from layer (m) + mass , & ! total snow mass from tracers (kg/m^2) + massi ! mass change factor character(len=*),parameter :: subname='(freeboard)' @@ -1843,13 +1891,20 @@ subroutine freeboard (nslyr, & dhs = min(dhsn, dzs(k)) ! snow to remove from layer hsn = hsn - dhs dsnow = dsnow - dhs ! new snow + + ! remove both ice and liquid from snow to add to ice + mass = massice(k) + massliq(k) + massi = c0 + if (dzs(k) > puny) massi = max(c0, c1 - dhs/dzs(k)) + massice(k) = massice(k) * massi + massliq(k) = massliq(k) * massi +! massice(k) = max(c0, massice(k)) ! for roundoff +! massliq(k) = max(c0, massliq(k)) ! for roundoff + dzs(k) = dzs(k) - dhs dhsn = dhsn - dhs dhsn = max(dhsn,c0) hqs = hqs + dhs * zqsn(k) - ! remove both ice and liquid from snow to add to ice - smicetot(k) = smice(k)*dzs(k) - smliqtot(k) = smliq(k)*dzs(k) endif ! dhin > puny enddo @@ -2344,9 +2399,11 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & ! local variables integer (kind=int_kind) :: & + k , & ! layer index n ! category index real (kind=dbl_kind) :: & + rnslyr , & ! 1 / nslyr worka, workb ! temporary variables ! 2D coupler variables (computed for each category, then aggregated) @@ -2369,6 +2426,10 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & lhcoef , & ! transfer coefficient for latent heat rfrac ! water fraction retained for melt ponds + real (kind=dbl_kind), dimension(nslyr,ncat) :: & + massicen , & ! mass of ice in snow (kg/m^2) + massliqn ! mass of liquid in snow (kg/m^2) + real (kind=dbl_kind), dimension(n_iso) :: & Qrefn_iso , & ! isotope air sp hum reference level (kg/kg) fiso_ocnn , & ! isotope flux to ocean (kg/m^2/s) @@ -2550,6 +2611,22 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fsnow = fsnow* worka endif ! snwredist + !----------------------------------------------------------------- + ! solid and liquid components of snow mass + !----------------------------------------------------------------- + + massicen(:,:) = c0 + massliqn(:,:) = c0 + if (tr_snow) then + rnslyr = c1 / real(nslyr, dbl_kind) + do n = 1, ncat + do k = 1, nslyr + massicen(k,n) = l_smice(k,n) * vsnon(n) * rnslyr ! kg/m^2 + massliqn(k,n) = l_smliq(k,n) * vsnon(n) * rnslyr + enddo + enddo + endif + !----------------------------------------------------------------- ! Adjust frzmlt to account for ice-ocean heat fluxes since last ! call to coupler. @@ -2596,7 +2673,6 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & endif do n = 1, ncat - meltsn (n) = c0 melttn (n) = c0 meltbn (n) = c0 @@ -2720,14 +2796,16 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fhocnn=fhocnn, frain=frain, & meltt=melttn (n), melts=meltsn (n), & meltb=meltbn (n), meltsliq=l_meltsliq(n), & - smice=l_smice (:,n), smliq=l_smliq (:,n), & + smice=l_smice (:,n), massice=massicen(:,n), & + smliq=l_smliq (:,n), massliq=massliqn(:,n), & congel=congeln (n), snoice=snoicen (n), & mlt_onset=mlt_onset, frz_onset=frz_onset, & yday=yday, dsnow=dsnown (n), & prescribed_ice=prescribed_ice) if (icepack_warnings_aborted(subname)) then - call icepack_warnings_add(subname//' ice: Vertical thermo error: ') + write(warnstr,*) subname, ' ice: Vertical thermo error, cat ', n + call icepack_warnings_add(warnstr) return endif @@ -2776,13 +2854,17 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & H2_18O_ocn=l_H2_18O_ocn) if (icepack_warnings_aborted(subname)) return endif + endif ! aicen_init if (snwgrain .and. use_smliq_pnd) then - call drain_snow (dt = dt, nslyr = nslyr, & - vsnon = vsnon(n), aicen = aicen(n), & - smice = l_smice(:,n), smliq = l_smliq(:,n), & + call drain_snow (nslyr = nslyr, & + vsnon = vsnon(n), & + aicen = aicen(n), & + massice = massicen(:,n), & + massliq = massliqn(:,n), & meltsliq = l_meltsliq(n)) + if (icepack_warnings_aborted(subname)) return endif !----------------------------------------------------------------- @@ -2927,6 +3009,31 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & enddo ! ncat + !----------------------------------------------------------------- + ! reload snow mass tracers + !----------------------------------------------------------------- + + if (tr_snow) then + do n = 1, ncat + if (vsnon(n) > puny) then + do k = 1, nslyr + l_smice(k,n) = massicen(k,n) / (vsnon(n) * rnslyr) + l_smliq(k,n) = massliqn(k,n) / (vsnon(n) * rnslyr) + worka = l_smice(k,n) + l_smliq(k,n) + if (worka > puny) then + l_smice(k,n) = rhos * l_smice(k,n) / worka + l_smliq(k,n) = rhos * l_smliq(k,n) / worka + endif + enddo + else ! reset to default values + do k = 1, nslyr + l_smice(k,n) = rhos + l_smliq(k,n) = c0 + enddo + endif + enddo + endif + if (present(fsloss )) fsloss = l_fsloss if (present(isosno )) isosno = l_isosno if (present(isoice )) isoice = l_isoice From 9e1374f09eeeca6cf986e2cbec7b014609205638 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 29 Jul 2021 09:49:35 -0600 Subject: [PATCH 40/47] create temporary array for rsnow in shortwave calls to avoid array-out-of-bounds error when snwgrain=F --- configuration/driver/icedrv_init_column.F90 | 23 ++++++++++++++------- configuration/driver/icedrv_step.F90 | 22 +++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/configuration/driver/icedrv_init_column.F90 b/configuration/driver/icedrv_init_column.F90 index 0068ae021..580f154d2 100644 --- a/configuration/driver/icedrv_init_column.F90 +++ b/configuration/driver/icedrv_init_column.F90 @@ -122,17 +122,19 @@ subroutine init_shortwave logical (kind=log_kind) :: & l_print_point, & ! flag to print designated grid point diagnostics - dEdd_algae, & ! from icepack - modal_aero ! from icepack + dEdd_algae, & ! BGC - radiation interactions + modal_aero, & ! modal aerosol optical properties + snwgrain ! use variable snow grain size character (len=char_len) :: & - shortwave ! from icepack + shortwave ! shortwave formulation real (kind=dbl_kind), dimension(ncat) :: & fbri ! brine height to ice thickness real (kind=dbl_kind), allocatable, dimension(:,:) :: & - ztrcr_sw + rsnow , & ! snow grain radius + ztrcr_sw ! BGC tracers affecting radiation logical (kind=log_kind) :: tr_brine, tr_zaero, tr_bgc_N integer (kind=int_kind) :: nt_alvl, nt_apnd, nt_hpnd, nt_ipnd, nt_aero, & @@ -152,6 +154,7 @@ subroutine init_shortwave call icepack_query_parameters(shortwave_out=shortwave) call icepack_query_parameters(dEdd_algae_out=dEdd_algae) call icepack_query_parameters(modal_aero_out=modal_aero) + call icepack_query_parameters(snwgrain_out=snwgrain) call icepack_query_tracer_sizes(ntrcr_out=ntrcr, & nbtrcr_sw_out=nbtrcr_sw) call icepack_query_tracer_flags(tr_brine_out=tr_brine, & @@ -171,6 +174,7 @@ subroutine init_shortwave ! Initialize !----------------------------------------------------------------- + allocate(rsnow(nslyr,ncat)) allocate(ztrcr_sw(nbtrcr_sw, ncat)) fswpenln(:,:,:) = c0 @@ -224,10 +228,12 @@ subroutine init_shortwave call icedrv_system_abort(i, istep1, subname, __FILE__, __LINE__) endif - fbri(:) = c0 - ztrcr_sw(:,:) = c0 + fbri (:) = c0 + rsnow (:,:) = c0 + ztrcr_sw (:,:) = c0 do n = 1, ncat - if (tr_brine) fbri(n) = trcrn(i,nt_fbri,n) + if (tr_brine) fbri (n) = trcrn(i,nt_fbri,n) + if (snwgrain) rsnow (:,n) = trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,n) enddo if (tmask(i)) then @@ -277,7 +283,7 @@ subroutine init_shortwave albpndn=albpndn(i,:), apeffn=apeffn(i,:), & snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & - rsnow=trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & + rsnow=rsnow(:,:), & !history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point, & initonly = .true.) @@ -352,6 +358,7 @@ subroutine init_shortwave enddo ! i + deallocate(rsnow) deallocate(ztrcr_sw) end subroutine init_shortwave diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 94e69075e..28c574df4 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -960,13 +960,14 @@ subroutine step_radiation (dt) nlt_zaero_sw, nt_zaero, nt_bgc_N logical (kind=log_kind) :: & - tr_bgc_N, tr_zaero, tr_brine, dEdd_algae, modal_aero + tr_bgc_N, tr_zaero, tr_brine, dEdd_algae, modal_aero, snwgrain real (kind=dbl_kind), dimension(ncat) :: & - fbri ! brine height to ice thickness + fbri ! brine height to ice thickness real(kind= dbl_kind), dimension(:,:), allocatable :: & - ztrcr_sw + rsnow , & ! snow grain radius + ztrcr_sw ! BGC tracers affecting radiation logical (kind=log_kind) :: & l_print_point ! flag for printing debugging information @@ -1007,23 +1008,27 @@ subroutine step_radiation (dt) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) - call icepack_query_parameters(dEdd_algae_out=dEdd_algae, modal_aero_out=modal_aero) + call icepack_query_parameters(dEdd_algae_out=dEdd_algae, modal_aero_out=modal_aero, & + snwgrain_out=snwgrain) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) !----------------------------------------------------------------- + allocate(rsnow(nslyr,ncat)) allocate(ztrcr_sw(nbtrcr_sw,ncat)) l_print_point = .false. do i = 1, nx - fbri(:) = c0 - ztrcr_sw(:,:) = c0 + fbri (:) = c0 + rsnow (:,:) = c0 + ztrcr_sw (:,:) = c0 do n = 1, ncat - if (tr_brine) fbri(n) = trcrn(i,nt_fbri,n) + if (tr_brine) fbri (n) = trcrn(i,nt_fbri,n) + if (snwgrain) rsnow (:,n) = trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,n) enddo if (tmask(i)) then @@ -1069,7 +1074,7 @@ subroutine step_radiation (dt) albpndn=albpndn(i,:), apeffn=apeffn(i,:), & snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & - rsnow=trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & + rsnow=rsnow(:,:), & !history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point) @@ -1088,6 +1093,7 @@ subroutine step_radiation (dt) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__, line=__LINE__) + deallocate(rsnow) deallocate(ztrcr_sw) deallocate(nlt_zaero_sw) deallocate(nt_zaero) From 67fbfe1cf83f35d7445fec18b7a41138099f5c80 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 29 Jul 2021 14:54:15 -0600 Subject: [PATCH 41/47] reset default/initial tracer values when snow disappears; some cleanup --- columnphysics/icepack_itd.F90 | 18 +++++++------- columnphysics/icepack_therm_mushy.F90 | 8 +++---- columnphysics/icepack_therm_vertical.F90 | 30 ++++++++---------------- columnphysics/icepack_tracers.F90 | 19 +++++++++------ 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/columnphysics/icepack_itd.F90 b/columnphysics/icepack_itd.F90 index 5757b7bb3..9bee7e88a 100644 --- a/columnphysics/icepack_itd.F90 +++ b/columnphysics/icepack_itd.F90 @@ -28,11 +28,10 @@ module icepack_itd use icepack_kinds use icepack_parameters, only: c0, c1, c2, c3, c15, c25, c100, p1, p01, p001, p5, puny use icepack_parameters, only: Lfresh, rhos, ice_ref_salinity, hs_min, cp_ice, Tocnfrz, rhoi - use icepack_parameters, only: rhosi, sk_l, hs_ssl, min_salin + use icepack_parameters, only: rhosi, sk_l, hs_ssl, min_salin, rsnw_fall use icepack_tracers, only: nt_Tsfc, nt_qice, nt_qsno, nt_aero, nt_isosno, nt_isoice use icepack_tracers, only: nt_apnd, nt_hpnd, nt_fbri, tr_brine, nt_bgc_S, bio_index - use icepack_tracers, only: n_iso - use icepack_tracers, only: tr_iso + use icepack_tracers, only: n_iso, tr_iso, tr_snow, nt_smice, nt_rsnw use icepack_tracers, only: icepack_compute_tracers use icepack_parameters, only: solve_zsal, skl_bgc, z_tracers use icepack_parameters, only: kcatbound, kitd @@ -1230,11 +1229,14 @@ subroutine zap_small_areas (dt, ntrcr, & if (ntrcr >= 2) then do it = 2, ntrcr - if (tr_brine .and. it == nt_fbri) then - trcrn(it,n) = c1 - else - trcrn(it,n) = c0 - endif + trcrn(it,n) = c0 + enddo + endif + if (tr_brine) trcrn(nt_fbri,n) = c1 + if (tr_snow) then + do k = 1, nslyr + trcrn(nt_smice+k-1,n) = rhos + trcrn(nt_rsnw +k-1,n) = rsnw_fall enddo endif first_ice(n) = .true. diff --git a/columnphysics/icepack_therm_mushy.F90 b/columnphysics/icepack_therm_mushy.F90 index f34947579..54a228ca3 100644 --- a/columnphysics/icepack_therm_mushy.F90 +++ b/columnphysics/icepack_therm_mushy.F90 @@ -1,6 +1,6 @@ !======================================================================= -module icepack_therm_mushy + module icepack_therm_mushy use icepack_kinds use icepack_parameters, only: c0, c1, c2, c8, c10 @@ -35,7 +35,7 @@ module icepack_therm_mushy !======================================================================= -contains + contains !======================================================================= @@ -3282,7 +3282,7 @@ subroutine flood_ice(hsn, hin, & ! for now, do not use variable snow density ! snow_mass = c0 -! if (tr_snow) then +! if (snwgrain) then ! do k = 1,nslyr ! snow_mass = snow_mass + (smice(k) + smliq(k)) * hslyr ! enddo @@ -3569,6 +3569,6 @@ end subroutine update_vertical_tracers_ice !======================================================================= -end module icepack_therm_mushy + end module icepack_therm_mushy !======================================================================= diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index bcbcde37e..7b019349c 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -1567,8 +1567,7 @@ subroutine thickness_changes (nilyr, nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice, massice, & - smliq, massliq) + massice, massliq) if (icepack_warnings_aborted(subname)) return !------------------------------------------------------------------- @@ -1583,7 +1582,7 @@ subroutine thickness_changes (nilyr, nslyr, & smice(k) = massice(k) / dzs(k) smliq(k) = massliq(k) / dzs(k) else - smice(k) = c0 + smice(k) = c0 ! reset to rhos below smliq(k) = c0 massice(k) = c0 massliq(k) = c0 @@ -1736,19 +1735,13 @@ subroutine thickness_changes (nilyr, nslyr, & zs1(:), zs2(:), & hslyr, hsn, & smliq(:)) - endif - if (icepack_warnings_aborted(subname)) return - - !------------------------------------------------------------------- - ! Update snow mass - !------------------------------------------------------------------- - - if (snwgrain) then + ! Update snow mass do k = 1, nslyr massice(k) = smice(k) * hslyr massliq(k) = smliq(k) * hslyr enddo endif + if (icepack_warnings_aborted(subname)) return endif ! nslyr > 1 @@ -1764,7 +1757,7 @@ subroutine thickness_changes (nilyr, nslyr, & zqsn(k) = -rhos*Lfresh if (snwgrain) then meltsliq = meltsliq + massice(k) ! add to meltponds - smice(k) = c0 + smice(k) = rhos smliq(k) = c0 endif enddo @@ -1816,8 +1809,7 @@ subroutine freeboard (nslyr, & zqin, zqsn, & dzi, dzs, & dsnow, & - smice, massice, & - smliq, massliq) + massice, massliq) integer (kind=int_kind), intent(in) :: & nslyr ! number of snow layers @@ -1837,9 +1829,7 @@ subroutine freeboard (nslyr, & hsn ! snow thickness (m) real (kind=dbl_kind), dimension (:), intent(in) :: & - zqsn , & ! snow layer enthalpy (J m-3) - smice , & ! liquid water mass tracer in snow (kg/m^3) - smliq ! ice mass tracer in snow (kg/m^3) + zqsn ! snow layer enthalpy (J m-3) real (kind=dbl_kind), dimension (:), intent(inout) :: & zqin , & ! ice layer enthalpy (J m-3) @@ -1874,7 +1864,7 @@ subroutine freeboard (nslyr, & dhsn = c0 hqs = c0 - wk1 = hsn - hin*(rhow-rhoi)/rhos ! not yet consistent with smice/smliq !echmod - fix this + wk1 = hsn - hin*(rhow-rhoi)/rhos ! not yet consistent with smice/smliq if (wk1 > puny .and. hsn > puny) then ! snow below freeboard dhsn = min(wk1*rhoi/rhow, hsn) ! snow to remove @@ -2617,7 +2607,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & massicen(:,:) = c0 massliqn(:,:) = c0 - if (tr_snow) then + if (snwgrain) then rnslyr = c1 / real(nslyr, dbl_kind) do n = 1, ncat do k = 1, nslyr @@ -3013,7 +3003,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & ! reload snow mass tracers !----------------------------------------------------------------- - if (tr_snow) then + if (snwgrain) then do n = 1, ncat if (vsnon(n) > puny) then do k = 1, nslyr diff --git a/columnphysics/icepack_tracers.F90 b/columnphysics/icepack_tracers.F90 index 05ffde9b7..e9664585d 100644 --- a/columnphysics/icepack_tracers.F90 +++ b/columnphysics/icepack_tracers.F90 @@ -7,7 +7,7 @@ module icepack_tracers use icepack_kinds - use icepack_parameters, only: c0, c1, puny, Tocnfrz + use icepack_parameters, only: c0, c1, puny, Tocnfrz, rhos, rsnw_fall use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -1204,10 +1204,10 @@ end subroutine icepack_write_tracer_sizes ! Given atrcrn = aicen*trcrn (or vicen*trcrn, vsnon*trcrn), compute trcrn. subroutine icepack_compute_tracers (ntrcr, trcr_depend, & - atrcrn, aicen, & - vicen, vsnon, & - trcr_base, n_trcr_strata, & - nt_strata, trcrn) + atrcrn, aicen, & + vicen, vsnon, & + trcr_base, n_trcr_strata, & + nt_strata, trcrn) integer (kind=int_kind), intent(in) :: & ntrcr ! number of tracers in use @@ -1288,13 +1288,18 @@ subroutine icepack_compute_tracers (ntrcr, trcr_depend, & endif enddo endif - if (vicen <= c0 .and. it == nt_fbri) trcrn(it) = c1 endif ! trcr_depend=0 enddo - end subroutine icepack_compute_tracers + if (vicen <= c0 .and. tr_brine) trcrn(nt_fbri) = c1 + if (vsnon <= c0 .and. tr_snow) then + trcrn(nt_rsnw :nt_rsnw +nslyr-1) = rsnw_fall + trcrn(nt_smice:nt_smice+nslyr-1) = rhos + endif + + end subroutine icepack_compute_tracers !======================================================================= From 97c0c31da658e08b3f7a96dae48dd1707b1644e2 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 30 Jul 2021 09:52:39 -0600 Subject: [PATCH 42/47] Bug fix for bulk redistribution precipitation factor. Commented out shortwave modification for bulk redistribution - it should not be used for production runs without more careful analysis of the energy balance between level and ridged ice. --- columnphysics/icepack_shortwave.F90 | 45 +++++++++++++----------- columnphysics/icepack_therm_vertical.F90 | 4 +-- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index a36e59fab..423dae86e 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -1032,26 +1032,31 @@ subroutine run_dEdd(dt, ncat, & elseif (tr_pond_lvl) then hsnlvl = hsn ! initialize - if (trim(snwredist) == 'bulk') then - hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) - ! snow volume over level ice - alvl = aicen(n) * alvln(n) - if (alvl > puny) then - vsn = hsnlvl * alvl - else - vsn = vsnon(n) - alvl = aicen(n) - endif - ! set snow properties over level ice - call shortwave_dEdd_set_snow(nslyr, R_snw, & - dT_mlt, rsnw_mlt, & - alvl, vsn, & - Tsfcn(n), fsn, & - hs0, hsnlvl, & - rhosnwn(:), rsnwn(:), & - rsnow(:,n)) - if (icepack_warnings_aborted(subname)) return - endif ! snwredist +! if (trim(snwredist) == 'bulksw') then +! ! This option is here for testing purposes only. +! ! It assumes a fraction of the snow is moved from level ice to ridges, +! ! but only the snow depth over the level ice is used for the radiative calculation. +! ! Since the deeper snow on the ridged area is not accounted for, this option is +! ! internally inconsistent. +! hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) +! ! snow volume over level ice +! alvl = aicen(n) * alvln(n) +! if (alvl > puny) then +! vsn = hsnlvl * alvl +! else +! vsn = vsnon(n) +! alvl = aicen(n) +! endif +! ! set snow properties over level ice +! call shortwave_dEdd_set_snow(nslyr, R_snw, & +! dT_mlt, rsnw_mlt, & +! alvl, vsn, & +! Tsfcn(n), fsn, & +! hs0, hsnlvl, & +! rhosnwn(:), rsnwn(:), & +! rsnow(:,n)) +! if (icepack_warnings_aborted(subname)) return +! endif ! snwredist fpn = c0 ! fraction of ice covered in pond hpn = c0 ! pond depth over fpn diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 7b019349c..5cdb347b2 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2597,8 +2597,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & worka = worka + alvl(n) enddo worka = worka * snwlvlfac/(c1+snwlvlfac) - l_fsloss = l_fsloss + fsnow*(c1-worka) - fsnow = fsnow* worka + l_fsloss = l_fsloss + fsnow* worka + fsnow = fsnow*(c1-worka) endif ! snwredist !----------------------------------------------------------------- From 0f8407b9caabf74c3fe12f4c0e878b20d6818e0a Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 30 Jul 2021 11:21:26 -0600 Subject: [PATCH 43/47] Another bug fix for bulk redistribution precipitation factor - average alvl weighted by aice. Reinstated shortwave modification for bulk redistribution - it works the same as for ITDrdg. Updated documentation. --- columnphysics/icepack_shortwave.F90 | 46 +++++++++++------------- columnphysics/icepack_snow.F90 | 4 +-- columnphysics/icepack_therm_vertical.F90 | 14 ++++---- doc/source/science_guide/sg_snow.rst | 6 ++-- 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 423dae86e..ac2d7b09b 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -1030,33 +1030,27 @@ subroutine run_dEdd(dt, ncat, & fsn = min(fsn, c1-fpn) apeffn(n) = fpn ! for history elseif (tr_pond_lvl) then - hsnlvl = hsn ! initialize -! if (trim(snwredist) == 'bulksw') then -! ! This option is here for testing purposes only. -! ! It assumes a fraction of the snow is moved from level ice to ridges, -! ! but only the snow depth over the level ice is used for the radiative calculation. -! ! Since the deeper snow on the ridged area is not accounted for, this option is -! ! internally inconsistent. -! hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) -! ! snow volume over level ice -! alvl = aicen(n) * alvln(n) -! if (alvl > puny) then -! vsn = hsnlvl * alvl -! else -! vsn = vsnon(n) -! alvl = aicen(n) -! endif -! ! set snow properties over level ice -! call shortwave_dEdd_set_snow(nslyr, R_snw, & -! dT_mlt, rsnw_mlt, & -! alvl, vsn, & -! Tsfcn(n), fsn, & -! hs0, hsnlvl, & -! rhosnwn(:), rsnwn(:), & -! rsnow(:,n)) -! if (icepack_warnings_aborted(subname)) return -! endif ! snwredist + if (trim(snwredist) == 'bulk') then + hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln(n))) + ! snow volume over level ice + alvl = aicen(n) * alvln(n) + if (alvl > puny) then + vsn = hsnlvl * alvl + else + vsn = vsnon(n) + alvl = aicen(n) + endif + ! set snow properties over level ice + call shortwave_dEdd_set_snow(nslyr, R_snw, & + dT_mlt, rsnw_mlt, & + alvl, vsn, & + Tsfcn(n), fsn, & + hs0, hsnlvl, & + rhosnwn(:), rsnwn(:), & + rsnow(:,n)) + if (icepack_warnings_aborted(subname)) return + endif ! snwredist fpn = c0 ! fraction of ice covered in pond hpn = c0 ! pond depth over fpn diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index 7708eb8f4..6cbd3e820 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -233,7 +233,7 @@ subroutine icepack_step_snow(dt, nilyr, & real (kind=dbl_kind), intent(inout) :: & fresh , & ! fresh water flux to ocean (kg/m^2/s) fhocn , & ! net heat flux to ocean (W/m^2) - fsloss ! snow loss to leads (kg/m^2/s) + fsloss ! rate of snow loss to leads (kg/m^2/s) real (kind=dbl_kind), dimension(:), intent(inout) :: & vsnon ! snow volume (m) @@ -464,7 +464,7 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & real (kind=dbl_kind), intent(inout) :: & fresh , & ! fresh water flux to ocean (kg/m^2/s) fhocn , & ! net heat flux to ocean (W/m^2) - fsloss ! snow loss to leads (kg/m^2/s) + fsloss ! rate of snow loss to leads (kg/m^2/s) real (kind=dbl_kind), dimension(:), intent(inout) :: & vsn ! snow volume (m) diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 5cdb347b2..0028d47ab 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2305,7 +2305,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) fswthru_idf , & ! nir dif shortwave penetrating to ocean (W/m^2) dsnow , & ! change in snow depth (m/step-->cm/day) - fsloss ! fraction of snow lost to leads + fsloss ! rate of snow loss to leads (kg/m^2/s) real (kind=dbl_kind), dimension(:), optional, intent(inout) :: & Qa_iso , & ! isotope specific humidity (kg/kg) @@ -2443,7 +2443,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_smliq ! tracer for mass of liquid in snow (kg/m^3) real (kind=dbl_kind) :: & - l_fsloss , & ! fraction of snow lost to leads + l_fsloss , & ! rate of snow loss to leads (kg/m^2/s) l_HDO_ocn , & ! local ocean concentration of HDO (kg/kg) l_H2_16O_ocn, & ! local ocean concentration of H2_16O (kg/kg) l_H2_18O_ocn ! local ocean concentration of H2_18O (kg/kg) @@ -2593,10 +2593,12 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & if (trim(snwredist) == 'bulk') then worka = c0 - do n = 1, ncat - worka = worka + alvl(n) - enddo - worka = worka * snwlvlfac/(c1+snwlvlfac) + if (aice > puny) then + do n = 1, ncat + worka = worka + alvl(n)*aicen(n) + enddo + worka = worka * (snwlvlfac/(c1+snwlvlfac)) / aice + endif l_fsloss = l_fsloss + fsnow* worka fsnow = fsnow*(c1-worka) endif ! snwredist diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 7945fd106..7b0ea3dce 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -40,14 +40,14 @@ Bulk snow redistribution :cite:`Sturm02` noted that on average during the SHEBA experiment, snow near ridged ice was 30% deeper than snow on undeformed ice. Using this rule of thumb, we can reduce the amount of snow on level ice in the model by reducing the snowfall rate over the sea ice and assuming the removed snow volume passes into the ocean through leads, instantaneously. This approach takes into account the area of open water available, as in the original code, by employing a precipitation flux in units of kg m :math:`^{-2}` s :math:`^{-1}`, which accumulates snow only on the ice-covered area of the grid cell. -There are two levels of sophistication at which this approach can be accomplished: (1) assuming the snow removed from the level ice area is deposited into leads, and (2) assuming the snow removed from the level ice area is deposited onto ridges. Case (1) affects both the radiative and thermodynamic calculations by reducing the total amount of snow on the ice. Case (2) affects the radiative calculation directly, by possibly exposing more bare ice or melt ponds, but it affects the thermodynamic (conduction) calculation only through the altered radiative absorption, since the snow is always assumed to be equally deep over both level and deformed ice for the thermodynamic calculation. +This approach affects the simulation in two ways: (1) the snow removed from the level ice area is deposited into leads, and (2) using the snow remaining on the level ice area to adjust the effective melt pond and bare ice areas. Case (1) affects both the radiative and thermodynamic calculations by reducing the total amount of snow on the ice. Case (2) affects the radiative calculation directly, by possibly exposing more bare ice or melt ponds, but it affects the thermodynamic (conduction) calculation only through the altered radiative absorption, since the snow is always assumed to be equally deep over both level and deformed ice for the thermodynamic calculation. When ``snwredist`` = ``bulk``, snow loss to leads is accomplished simply by reducing the volume of snowfall reaching the ice: .. math:: - f_{s}^\prime = {f_s a_{lvl} \left({p\over{1+p}}\right)}, + f_{s}^\prime = {f_s \left[ a_{lvl} \left({p\over{1+p}}\right)\right]}, -where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the level-ice tracer value, and primed quantities represent their modified values. +where :math:`f_s` is the snowfall rate, :math:`a_{lvl}` is the average level-ice tracer value, and primed quantities represent their modified values. Snow is redistributed between level and ridged ice within a single thickness category by solving a pair of equations for the modified level- and ridged-ice snow depths in terms of the original snow depth: From 42fd34b4beedf7951b9e76df699bec808dca714b Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Wed, 4 Aug 2021 09:45:18 -0600 Subject: [PATCH 44/47] cleanup --- columnphysics/icepack_shortwave.F90 | 40 ++++++++++++------------ columnphysics/icepack_snow.F90 | 8 ++--- columnphysics/icepack_therm_vertical.F90 | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index ac2d7b09b..70155c625 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -990,7 +990,7 @@ subroutine run_dEdd(dt, ncat, & do n = 1, ncat - ! note that rhoswn, rsnw, fp, hp and Sswabs ARE NOT dimensioned with ncat + ! note that rhosnwn, rsnw, fp, hp and Sswabs ARE NOT dimensioned with ncat ! BPB 19 Dec 2006 ! set snow properties @@ -3667,31 +3667,31 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & if (snwgrain) then ! use snow grain tracer - do ks = 1, nslyr + do ks = 1, nslyr rsnw(ks) = max(rsnw_fall,rsnow(ks)) rsnw(ks) = min(rsnw_tmax,rsnow(ks)) rhosnw(ks) = rhos - enddo + enddo else - ! bare ice, temperature dependence - dTs = Timelt - Tsfc - fT = -min(dTs/dT_mlt-c1,c0) - ! tune nonmelt snow grain radius if desired: note that - ! the sign is negative so that if R_snw is 1, then the - ! snow grain radius is reduced and thus albedo increased. - rsnw_nm = rsnw_nonmelt - R_snw*rsnw_sig - rsnw_nm = max(rsnw_nm, rsnw_fresh) - rsnw_nm = min(rsnw_nm, rsnw_mlt) - do ks = 1, nslyr - ! snow density ccsm3 constant value - rhosnw(ks) = rhos - ! snow grain radius between rsnw_nonmelt and rsnw_mlt - rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT - rsnw(ks) = max(rsnw(ks), rsnw_fresh) - rsnw(ks) = min(rsnw(ks), rsnw_mlt) - enddo ! ks + ! bare ice, temperature dependence + dTs = Timelt - Tsfc + fT = -min(dTs/dT_mlt-c1,c0) + ! tune nonmelt snow grain radius if desired: note that + ! the sign is negative so that if R_snw is 1, then the + ! snow grain radius is reduced and thus albedo increased. + rsnw_nm = rsnw_nonmelt - R_snw*rsnw_sig + rsnw_nm = max(rsnw_nm, rsnw_fresh) + rsnw_nm = min(rsnw_nm, rsnw_mlt) + do ks = 1, nslyr + ! snow density ccsm3 constant value + rhosnw(ks) = rhos + ! snow grain radius between rsnw_nonmelt and rsnw_mlt + rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT + rsnw(ks) = max(rsnw(ks), rsnw_fresh) + rsnw(ks) = min(rsnw(ks), rsnw_mlt) + enddo ! ks endif ! snwgrain diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index 6cbd3e820..cb85a0dae 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -510,9 +510,9 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & de , & ! change in energy (J/m^2) al, ar , & ! areas of level and ridged ice hlvl, hrdg, & ! thicknesses of level and ridged ice - tmp1, tmp2, & ! temporary values - tmp3, tmp4, & ! temporary values - tmp5 , & ! temporary values + tmp1, tmp2, & ! temporary values + tmp3, tmp4, & ! temporary values + tmp5 , & ! temporary values work ! temporary value real (kind=dbl_kind), dimension(ncat) :: & @@ -615,7 +615,7 @@ subroutine snow_redist(dt, nslyr, ncat, wind, ain, vin, vsn, zqsn, & !----------------------------------------------------------------- flost = (c1 - suma) * exp(-ITDsd/refsd) -!echmod flost = c0 +! flost = c0 ! echmod for testing alost = c1 - suma * (c1-flost) !----------------------------------------------------------------- diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index 0028d47ab..a494403ec 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -29,7 +29,7 @@ module icepack_therm_vertical use icepack_parameters, only: phi_i_mushy, floeshape, floediam, use_smliq_pnd, snwredist use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso - use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo, tr_snow + use icepack_tracers, only: tr_pond_cesm, tr_pond_lvl, tr_pond_topo use icepack_tracers, only: n_aero, n_iso use icepack_therm_shared, only: ferrmax, l_brine From 065425f3187c87db2408e04befa327bcce722b60 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Thu, 5 Aug 2021 12:02:24 -0600 Subject: [PATCH 45/47] remove rnsw_dEdd array, load tracer instead; use rsnw_fall instead of rsnw_fresh in dEdd, set dEdd default value in namelist and tr_snow value in options --- columnphysics/icepack_shortwave.F90 | 38 +++++-------------- configuration/driver/icedrv_init_column.F90 | 1 - configuration/driver/icedrv_step.F90 | 1 - configuration/scripts/icepack_in | 2 +- .../scripts/options/set_nml.snwITDrdg | 9 ++++- .../scripts/options/set_nml.snwgrain | 2 + doc/source/science_guide/sg_tracers.rst | 3 +- 7 files changed, 23 insertions(+), 33 deletions(-) diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 70155c625..d1d86621e 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -805,7 +805,6 @@ subroutine run_dEdd(dt, ncat, & snowfracn, & dhsn, ffracn, & rsnow, & - rsnw_dEddn, & l_print_point, & initonly) @@ -877,12 +876,10 @@ subroutine run_dEdd(dt, ncat, & ipndn ! pond refrozen lid thickness (m) real(kind=dbl_kind), dimension(:,:), intent(in) :: & - rsnow, & ! snow grain radius tracer (10^-6 m) aeron, & ! aerosols (kg/m^3) trcrn_bgcsw ! zaerosols (kg/m^3) + chlorophyll on shorthwave grid real(kind=dbl_kind), dimension(:), intent(inout) :: & - rsnw_dEddn, & ! constant snow grain radius (10^-6 m) ffracn,& ! fraction of fsurfn used to melt ipond dhsn ! depth difference for snow on sea ice and pond ice @@ -910,6 +907,7 @@ subroutine run_dEdd(dt, ncat, & fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) real(kind=dbl_kind), dimension(:,:), intent(inout) :: & + rsnow , & ! snow grain radius tracer (10^-6 m) Sswabsn , & ! SW radiation absorbed in snow layers (W m-2) Iswabsn , & ! SW radiation absorbed in ice layers (W m-2) fswpenln ! visible SW entering ice layers (W m-2) @@ -1000,7 +998,6 @@ subroutine run_dEdd(dt, ncat, & rsnwn(:) = c0 apeffn(n) = c0 ! for history snowfracn(n) = c0 ! for history - rsnw_dEddn(n) = c0 ! for history if (aicen(n) > puny) then @@ -1184,9 +1181,8 @@ subroutine run_dEdd(dt, ncat, & if (icepack_warnings_aborted(subname)) return if (.not. snwgrain) then - rnslyr = c1/min(c1,(real(nslyr,kind=dbl_kind))) do k = 1,nslyr - rsnw_dEddn(n) = rsnw_dEddn(n) + rsnwn(k)*rnslyr + rsnow(k,n) = rsnwn(k) ! for history enddo endif @@ -3649,7 +3645,6 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & real (kind=dbl_kind), parameter :: & ! units for the following are 1.e-6 m (micro-meters) - rsnw_fresh = 100._dbl_kind, & ! freshly-fallen snow grain radius rsnw_nonmelt = 500._dbl_kind, & ! nonmelt snow grain radius rsnw_sig = 250._dbl_kind ! assumed sigma for snow grain radius @@ -3682,14 +3677,14 @@ subroutine shortwave_dEdd_set_snow(nslyr, R_snw, & ! the sign is negative so that if R_snw is 1, then the ! snow grain radius is reduced and thus albedo increased. rsnw_nm = rsnw_nonmelt - R_snw*rsnw_sig - rsnw_nm = max(rsnw_nm, rsnw_fresh) + rsnw_nm = max(rsnw_nm, rsnw_fall) rsnw_nm = min(rsnw_nm, rsnw_mlt) do ks = 1, nslyr ! snow density ccsm3 constant value rhosnw(ks) = rhos ! snow grain radius between rsnw_nonmelt and rsnw_mlt rsnw(ks) = rsnw_nm + (rsnw_mlt-rsnw_nm)*fT - rsnw(ks) = max(rsnw(ks), rsnw_fresh) + rsnw(ks) = max(rsnw(ks), rsnw_fall) rsnw(ks) = min(rsnw(ks), rsnw_mlt) enddo ! ks @@ -4066,8 +4061,8 @@ subroutine icepack_step_radiation (dt, ncat, & albpndn, apeffn, & snowfracn, & dhsn, ffracn, & - rsnow, rsnw_dEddn,& - l_print_point, & + rsnow, & + l_print_point, & initonly) integer (kind=int_kind), intent(in) :: & @@ -4170,11 +4165,8 @@ subroutine icepack_step_radiation (dt, ncat, & dEdd_algae , & ! .true. use prognostic chla in dEdd modal_aero ! .true. use modal aerosol optical treatment - real (kind=dbl_kind), dimension(:,:), intent(in), optional :: & - rsnow ! snow grain radius tracer (10^-6 m) - - real(kind=dbl_kind), dimension(:), intent(inout), optional :: & - rsnw_dEddn ! constant snow grain radius (10^-6 m) + real (kind=dbl_kind), dimension(:,:), intent(inout), optional :: & + rsnow ! snow grain radius tracer (10^-6 m) logical (kind=log_kind), optional :: & initonly ! flag to indicate init only, default is false @@ -4197,8 +4189,7 @@ subroutine icepack_step_radiation (dt, ncat, & l_fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) l_fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) l_fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - l_fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) - l_rsnw_dEddn ! constant snow grain radius (10^-6 m) + l_fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) real (kind=dbl_kind), dimension(:,:), allocatable :: & l_rsnow ! snow grain radius tracer (10^-6 m) @@ -4219,11 +4210,7 @@ subroutine icepack_step_radiation (dt, ncat, & allocate(l_rsnow (nslyr,ncat)) l_rsnow = c0 - if (snwgrain .and. present(rsnow)) l_rsnow = rsnow - - allocate(l_rsnw_dEddn (ncat)) - l_rsnw_dEddn = c0 - if (present(rsnw_dEddn)) l_rsnw_dEddn = rsnw_dEddn + if (present(rsnow)) l_rsnow = rsnow ! Initialize do n = 1, ncat @@ -4310,7 +4297,6 @@ subroutine icepack_step_radiation (dt, ncat, & dhsn=dhsn, & ffracn=ffracn, & rsnow=l_rsnow, & - rsnw_dEddn=l_rsnw_dEddn, & l_print_point=l_print_point, & initonly=linitonly) if (icepack_warnings_aborted(subname)) return @@ -4397,11 +4383,7 @@ subroutine icepack_step_radiation (dt, ncat, & deallocate(l_fswthrun_vdf) deallocate(l_fswthrun_idr) deallocate(l_fswthrun_idf) - - if (present(rsnw_dEddn)) rsnw_dEddn = l_rsnw_dEddn - deallocate(l_rsnow) - deallocate(l_rsnw_dEddn) end subroutine icepack_step_radiation diff --git a/configuration/driver/icedrv_init_column.F90 b/configuration/driver/icedrv_init_column.F90 index 580f154d2..1d90281f4 100644 --- a/configuration/driver/icedrv_init_column.F90 +++ b/configuration/driver/icedrv_init_column.F90 @@ -284,7 +284,6 @@ subroutine init_shortwave snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & rsnow=rsnow(:,:), & -!history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point, & initonly = .true.) endif diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 28c574df4..b6a2e71fe 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -1075,7 +1075,6 @@ subroutine step_radiation (dt) snowfracn=snowfracn(i,:), & dhsn=dhsn(i,:), ffracn=ffracn(i,:), & rsnow=rsnow(:,:), & -!history rsnw_dEddn=rsnw_dEddn(i,:), & l_print_point=l_print_point) endif ! tmask diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 401b41047..ef945a326 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -83,7 +83,7 @@ snwredist = 'none' snwgrain = .false. use_smliq_pnd = .false. - rsnw_fall = 54.526 + rsnw_fall = 100.0 rsnw_tmax = 1500.0 rhosnew = 100.0 rhosmin = 100.0 diff --git a/configuration/scripts/options/set_nml.snwITDrdg b/configuration/scripts/options/set_nml.snwITDrdg index 509cd403c..c802c51fe 100644 --- a/configuration/scripts/options/set_nml.snwITDrdg +++ b/configuration/scripts/options/set_nml.snwITDrdg @@ -1,2 +1,9 @@ -tr_snow = .true. +tr_snow = .true. snwredist = 'ITDrdg' +nslyr = 5 +rhosnew = 100.0 +rhosmin = 100.0 +rhosmax = 450.0 +windmin = 10.0 +drhosdwind = 27.3 +snwlvlfac = 0.3 diff --git a/configuration/scripts/options/set_nml.snwgrain b/configuration/scripts/options/set_nml.snwgrain index ebbab032b..386a3238b 100644 --- a/configuration/scripts/options/set_nml.snwgrain +++ b/configuration/scripts/options/set_nml.snwgrain @@ -1,4 +1,6 @@ tr_snow = .true. snwgrain = .true. use_smliq_pnd = .true. +rsnw_fall = 54.526 +rsnw_tmax = 1500.0 diff --git a/doc/source/science_guide/sg_tracers.rst b/doc/source/science_guide/sg_tracers.rst index 4503da399..77d3fd959 100755 --- a/doc/source/science_guide/sg_tracers.rst +++ b/doc/source/science_guide/sg_tracers.rst @@ -10,7 +10,8 @@ required (surface temperature and thickness, salinity and enthalpy of ice and sn and many others are options. For instance, there are tracers to track the age of the ice; the area of first-year ice, fractions of ice area and volume that are level, from which the amount of deformed ice can be calculated; pond area, pond volume and volume of ice covering ponds; -a prognostic floe size distribution; aerosols, water isotopes, and numerous other biogeochemical tracers. +a prognostic floe size distribution; snow density, grain size, and ice and liquid content; +aerosols, water isotopes, and numerous other biogeochemical tracers. Most of these tracers are presented in later sections. Here we describe the ice age tracers and how tracers may depend on other tracers, using the pond tracers as an example. From 5a2e604574980d2c70f189070a9d568fd319da32 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 6 Aug 2021 09:20:12 -0600 Subject: [PATCH 46/47] Removed variables that were only for history output, instead using the tracer array directly; the snow_effective_density subroutine was then also unnecessary. --- columnphysics/icepack_snow.F90 | 119 +++--------------- configuration/driver/icedrv_arrays_column.F90 | 2 - configuration/driver/icedrv_step.F90 | 12 +- 3 files changed, 17 insertions(+), 116 deletions(-) diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index cb85a0dae..b0952b01b 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -202,9 +202,7 @@ subroutine icepack_step_snow(dt, nilyr, & zqsn, & alvl, vlvl, & smice, smliq, & - rhos_cmpn, rsnw, & - rhos_eff, rhos_effn, & - rhos_cmp, & + rsnw, rhos_cmpn, & fresh, fhocn, & fsloss, fsnow) @@ -243,18 +241,13 @@ subroutine icepack_step_snow(dt, nilyr, & smice , & ! tracer for mass of ice in snow (kg/m^3) smliq , & ! tracer for mass of liquid in snow (kg/m^3) rsnw , & ! snow grain radius (10^-6 m) - rhos_effn, & ! effective snow density: content (kg/m^3) rhos_cmpn ! effective snow density: compaction (kg/m^3) - real (kind=dbl_kind), intent(inout) :: & - rhos_eff , & ! mean effective snow density: content (kg/m^3) - rhos_cmp ! mean effective snow density: compaction (kg/m^3) - !autodocument_end ! local variables - integer (kind=int_kind) :: n + integer (kind=int_kind) :: k, n real (kind=dbl_kind), dimension(ncat) :: & zTin1, & ! ice upper layer temperature (C) @@ -268,25 +261,27 @@ subroutine icepack_step_snow(dt, nilyr, & character (len=*),parameter :: subname='(icepack_step_snow)' !----------------------------------------------------------------- - ! Compute effective density of snow + ! Initialize effective snow density (compaction) for new snow !----------------------------------------------------------------- - vsno = c0 - do n = 1, ncat - vsno = vsno + vsnon(n) - enddo - - call snow_effective_density(nslyr, ncat, & - vsnon, vsno, & - smice, smliq, & - rhos_effn, rhos_eff, & - rhos_cmpn, rhos_cmp) - if (icepack_warnings_aborted(subname)) return + if (trim(snwredist) /= 'none') then + do n = 1, ncat + do k = 1, nslyr + if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew + enddo + enddo + else + rhos_cmpn(:,:) = rhos + endif !----------------------------------------------------------------- ! Redistribute snow based on wind !----------------------------------------------------------------- + vsno = c0 + do n = 1, ncat + vsno = vsno + vsnon(n) + enddo tmp1 = rhos*vsno + fresh*dt if (snwredist(1:3) == 'ITD' .and. aice > puny) then @@ -343,88 +338,6 @@ end subroutine icepack_step_snow !======================================================================= -! Compute effective density of snow layers from ice, liquid water mass - - subroutine snow_effective_density(nslyr, ncat, & - vsnon, vsno, & - smice, smliq, & - rhos_effn, rhos_eff, & - rhos_cmpn, rhos_cmp) - - integer (kind=int_kind), intent(in) :: & - nslyr, & ! number of snow layers - ncat ! number of thickness categories - - real (kind=dbl_kind), dimension(:), intent(in) :: & - vsnon ! snow volume (m) - - real (kind=dbl_kind), intent(in) :: & - vsno ! total snow volume (m) - - real (kind=dbl_kind), dimension(:,:), & - intent(inout) :: & - smice , & ! tracer for mass of ice in snow (kg/m^3) - smliq , & ! tracer for mass of liquid in snow (kg/m^3) - rhos_effn, & ! effective snow density: content (kg/m^3) - rhos_cmpn ! effective snow density: compaction (kg/m^3) - - real (kind=dbl_kind), intent(inout) :: & - rhos_eff , & ! mean effective snow density: content (kg/m^3) - rhos_cmp ! mean effective snow density: compaction (kg/m^3) - - integer (kind=int_kind) :: & - k , & ! snow layer index - n , & ! ice thickness category index - cnt ! counter for snow presence - - character (len=*),parameter :: subname='(snow_effective_density)' - - rhos_eff = c0 - rhos_cmp = c0 - - if (vsno > puny) then - - !----------------------------------------------------------------- - ! Initialize effective snow density (compaction) for new snow - !----------------------------------------------------------------- - - if (trim(snwredist) /= 'none') then - do n = 1, ncat - do k = 1, nslyr - if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew - enddo - enddo - else - rhos_cmpn(:,:) = rhos - endif - - !----------------------------------------------------------------- - ! Compute average effective density of snow - !----------------------------------------------------------------- - - do n = 1, ncat - if (vsnon(n) > c0) then - do k = 1, nslyr - rhos_effn(k,n) = smice(k,n) + smliq(k,n) - rhos_eff = rhos_eff + vsnon(n)*rhos_effn(k,n) - rhos_cmp = rhos_cmp + vsnon(n)*rhos_cmpn(k,n) - enddo - endif - enddo - rhos_eff = rhos_eff/(vsno*real(nslyr,kind=dbl_kind)) - rhos_cmp = rhos_cmp/(vsno*real(nslyr,kind=dbl_kind)) - - else - - rhos_eff = rhos ! default to standard value - rhos_cmp = rhos - - endif ! vsno - - end subroutine snow_effective_density - -!======================================================================= - ! Snow redistribution by wind, based on O. Lecomte Ph.D. (2014). ! The original formulation: ! Snow in suspension depends on wind speed, density and the standard diff --git a/configuration/driver/icedrv_arrays_column.F90 b/configuration/driver/icedrv_arrays_column.F90 index d8452153c..9e3c49bba 100644 --- a/configuration/driver/icedrv_arrays_column.F90 +++ b/configuration/driver/icedrv_arrays_column.F90 @@ -65,8 +65,6 @@ module icedrv_arrays_column ! icepack_snow.F90 real (kind=dbl_kind), public, & dimension (nx) :: & - rhos_eff , & ! mean effective snow density: content (kg/m^3) - rhos_cmp , & ! mean effective snow density: compaction (kg/m^3) meltsliq ! snow melt mass (kg/m^2/step-->kg/m^2/day) real (kind=dbl_kind), & diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index b6a2e71fe..b807639bc 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -848,7 +848,6 @@ end subroutine step_dyn_ridge subroutine step_snow (dt) - use icedrv_arrays_column, only: rhos_eff, rhos_cmp use icedrv_domain_size, only: ncat, nslyr, nilyr, nx use icedrv_flux, only: wind, fresh, fhocn, fsloss, fsnow use icedrv_state, only: trcrn, vsno, vsnon, vicen, aicen, aice @@ -868,9 +867,6 @@ subroutine step_snow (dt) i, & ! horizontal index n ! category index - real (kind=dbl_kind), dimension(nslyr,ncat) :: & - rhos_effn ! snow effective density: content (kg/m^3) - character(len=*), parameter :: subname='(step_snow)' !----------------------------------------------------------------- @@ -892,10 +888,6 @@ subroutine step_snow (dt) do i = 1, nx - ! the effective snow density is not currently used outside of - ! the snow model, but is made available here for future use - rhos_effn(:,:) = c0 - call icepack_step_snow (dt, nilyr, & nslyr, ncat, & wind (i), aice (i), & @@ -907,10 +899,8 @@ subroutine step_snow (dt) trcrn(i,nt_alvl,:), trcrn(i,nt_vlvl,:), & trcrn(i,nt_smice:nt_smice+nslyr-1,:), & trcrn(i,nt_smliq:nt_smliq+nslyr-1,:), & - trcrn(i,nt_rhos:nt_rhos+nslyr-1,:), & trcrn(i,nt_rsnw:nt_rsnw+nslyr-1,:), & - rhos_eff (i), rhos_effn(:,:), & - rhos_cmp (i), & + trcrn(i,nt_rhos:nt_rhos+nslyr-1,:), & fresh (i), fhocn (i), & fsloss (i), fsnow (i)) enddo From 755b553f887a334b586f5a2a93d3d316c597cd6b Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 6 Aug 2021 14:15:56 -0600 Subject: [PATCH 47/47] initialize density tracer; fix history output for CICE --- columnphysics/icepack_flux.F90 | 4 +++ columnphysics/icepack_itd.F90 | 3 +- columnphysics/icepack_therm_vertical.F90 | 37 ++++++++++++++---------- columnphysics/icepack_tracers.F90 | 1 + 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/columnphysics/icepack_flux.F90 b/columnphysics/icepack_flux.F90 index 281d87e48..19864e46a 100644 --- a/columnphysics/icepack_flux.F90 +++ b/columnphysics/icepack_flux.F90 @@ -60,6 +60,7 @@ subroutine merge_fluxes (aicen, & meltt, melts, & meltb, dsnow, dsnown,& congel, snoice, & + meltsliq, meltsliqn, & Uref, Urefn, & Qref_iso, Qrefn_iso, & fiso_ocn, fiso_ocnn, & @@ -95,6 +96,7 @@ subroutine merge_fluxes (aicen, & melttn , & ! top ice melt (m) meltbn , & ! bottom ice melt (m) meltsn , & ! snow melt (m) + meltsliqn,& ! mass of snow melt (kg/m^2) dsnown , & ! change in snow depth (m) congeln , & ! congelation ice growth (m) snoicen ! snow-ice growth (m) @@ -126,6 +128,7 @@ subroutine merge_fluxes (aicen, & meltt , & ! top ice melt (m) meltb , & ! bottom ice melt (m) melts , & ! snow melt (m) + meltsliq, & ! mass of snow melt (kg/m^2) dsnow , & ! change in snow depth (m) congel , & ! congelation ice growth (m) snoice ! snow-ice growth (m) @@ -214,6 +217,7 @@ subroutine merge_fluxes (aicen, & meltt = meltt + melttn * aicen meltb = meltb + meltbn * aicen melts = melts + meltsn * aicen + meltsliq = meltsliq + meltsliqn * aicen dsnow = dsnow + dsnown * aicen congel = congel + congeln * aicen snoice = snoice + snoicen * aicen diff --git a/columnphysics/icepack_itd.F90 b/columnphysics/icepack_itd.F90 index 9bee7e88a..0c98b7ecf 100644 --- a/columnphysics/icepack_itd.F90 +++ b/columnphysics/icepack_itd.F90 @@ -31,7 +31,7 @@ module icepack_itd use icepack_parameters, only: rhosi, sk_l, hs_ssl, min_salin, rsnw_fall use icepack_tracers, only: nt_Tsfc, nt_qice, nt_qsno, nt_aero, nt_isosno, nt_isoice use icepack_tracers, only: nt_apnd, nt_hpnd, nt_fbri, tr_brine, nt_bgc_S, bio_index - use icepack_tracers, only: n_iso, tr_iso, tr_snow, nt_smice, nt_rsnw + use icepack_tracers, only: n_iso, tr_iso, tr_snow, nt_smice, nt_rsnw, nt_rhos use icepack_tracers, only: icepack_compute_tracers use icepack_parameters, only: solve_zsal, skl_bgc, z_tracers use icepack_parameters, only: kcatbound, kitd @@ -1235,6 +1235,7 @@ subroutine zap_small_areas (dt, ntrcr, & if (tr_brine) trcrn(nt_fbri,n) = c1 if (tr_snow) then do k = 1, nslyr + trcrn(nt_rhos +k-1,n) = rhos trcrn(nt_smice+k-1,n) = rhos trcrn(nt_rsnw +k-1,n) = rsnw_fall enddo diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index a494403ec..42cc66b85 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -2200,7 +2200,8 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & congel , congeln , & snoice , snoicen , & dsnow , dsnown , & - meltsliqn , rsnwn , & + meltsliq , meltsliqn , & + rsnwn , & smicen , smliqn , & lmask_n , lmask_s , & mlt_onset , frz_onset , & @@ -2305,6 +2306,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) fswthru_idf , & ! nir dif shortwave penetrating to ocean (W/m^2) dsnow , & ! change in snow depth (m/step-->cm/day) + meltsliq , & ! mass of snow melt (kg/m^2) fsloss ! rate of snow loss to leads (kg/m^2/s) real (kind=dbl_kind), dimension(:), optional, intent(inout) :: & @@ -2435,7 +2437,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_fiso_atm , & ! local isotope deposition rate (kg/m^2 s) l_fiso_ocn , & ! local isotope flux to ocean (kg/m^2/s) l_fiso_evap , & ! local isotope evaporation (kg/m^2/s) - l_meltsliq ! mass of snow melt (kg/m^2) + l_meltsliqn ! mass of snow melt (kg/m^2) real (kind=dbl_kind), allocatable, dimension(:,:) :: & l_rsnw , & ! snow grain radius (10^-6 m) @@ -2444,6 +2446,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & real (kind=dbl_kind) :: & l_fsloss , & ! rate of snow loss to leads (kg/m^2/s) + l_meltsliq , & ! mass of snow melt (kg/m^2) l_HDO_ocn , & ! local ocean concentration of HDO (kg/kg) l_H2_16O_ocn, & ! local ocean concentration of H2_16O (kg/kg) l_H2_18O_ocn ! local ocean concentration of H2_18O (kg/kg) @@ -2565,9 +2568,11 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & l_fswthrun_idf = c0 if (present(fswthrun_idf)) l_fswthrun_idf = fswthrun_idf - allocate(l_meltsliq(ncat)) - l_meltsliq = c0 - if (present(meltsliqn)) l_meltsliq = meltsliqn + allocate(l_meltsliqn(ncat)) + l_meltsliqn = c0 + if (present(meltsliqn)) l_meltsliqn = meltsliqn + l_meltsliq = c0 + if (present(meltsliq )) l_meltsliq = meltsliq allocate(l_rsnw(nslyr,ncat)) l_rsnw = rsnw_fall @@ -2787,7 +2792,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & freshn=freshn, fsaltn=fsaltn, & fhocnn=fhocnn, frain=frain, & meltt=melttn (n), melts=meltsn (n), & - meltb=meltbn (n), meltsliq=l_meltsliq(n), & + meltb=meltbn (n), meltsliq=l_meltsliqn(n),& smice=l_smice (:,n), massice=massicen(:,n), & smliq=l_smliq (:,n), massliq=massliqn(:,n), & congel=congeln (n), snoice=snoicen (n), & @@ -2855,7 +2860,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & aicen = aicen(n), & massice = massicen(:,n), & massliq = massliqn(:,n), & - meltsliq = l_meltsliq(n)) + meltsliq = l_meltsliqn(n)) if (icepack_warnings_aborted(subname)) return endif @@ -2882,7 +2887,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & Tsfcn=Tsfc (n), & apnd=apnd (n), & hpnd=hpnd (n), & - meltsliqn=l_meltsliq(n)) + meltsliqn=l_meltsliqn(n)) if (icepack_warnings_aborted(subname)) return elseif (tr_pond_lvl) then @@ -2911,7 +2916,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & apnd=apnd (n), & hpnd=hpnd (n), & ipnd=ipnd (n), & - meltsliqn=l_meltsliq(n)) + meltsliqn=l_meltsliqn(n)) if (icepack_warnings_aborted(subname)) return elseif (tr_pond_topo) then @@ -2922,7 +2927,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & rfrac = rfracmin + (rfracmax-rfracmin) * aicen(n) if (snwgrain .and. use_smliq_pnd) then pond = rfrac/rhofresh * (melttn(n)*rhoi & - + l_meltsliq(n)) + + l_meltsliqn(n)) else pond = rfrac/rhofresh * (melttn(n)*rhoi & + meltsn(n)*rhos & @@ -2987,8 +2992,9 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & meltt=meltt, melts=melts, & meltb=meltb, snoicen=snoicen(n),& dsnow=dsnow, dsnown=dsnown(n), & - congel=congel, & - snoice=snoice, & + congel=congel, snoice=snoice, & + meltsliq=l_meltsliq, & + meltsliqn=l_meltsliqn(n), & Uref=Uref, Urefn=Urefn, & Qref_iso=l_Qref_iso, & Qrefn_iso=Qrefn_iso, & @@ -3026,7 +3032,6 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & enddo endif - if (present(fsloss )) fsloss = l_fsloss if (present(isosno )) isosno = l_isosno if (present(isoice )) isoice = l_isoice if (present(Qa_iso )) Qa_iso = l_Qa_iso @@ -3042,7 +3047,9 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & if (present(fswthru_vdf )) fswthru_vdf = l_fswthru_vdf if (present(fswthru_idr )) fswthru_idr = l_fswthru_idr if (present(fswthru_idf )) fswthru_idf = l_fswthru_idf - if (present(meltsliqn )) meltsliqn = l_meltsliq + if (present(fsloss )) fsloss = l_fsloss + if (present(meltsliqn )) meltsliqn = l_meltsliqn + if (present(meltsliq )) meltsliq = l_meltsliq if (present(rsnwn )) rsnwn = l_rsnw if (present(smicen )) smicen = l_smice if (present(smliqn )) smliqn = l_smliq @@ -3057,7 +3064,7 @@ subroutine icepack_step_therm1(dt, ncat, nilyr, nslyr, & deallocate(l_fswthrun_vdf) deallocate(l_fswthrun_idr) deallocate(l_fswthrun_idf) - deallocate(l_meltsliq) + deallocate(l_meltsliqn) deallocate(l_rsnw) deallocate(l_smice) deallocate(l_smliq) diff --git a/columnphysics/icepack_tracers.F90 b/columnphysics/icepack_tracers.F90 index e9664585d..26c535e62 100644 --- a/columnphysics/icepack_tracers.F90 +++ b/columnphysics/icepack_tracers.F90 @@ -1297,6 +1297,7 @@ subroutine icepack_compute_tracers (ntrcr, trcr_depend, & if (vsnon <= c0 .and. tr_snow) then trcrn(nt_rsnw :nt_rsnw +nslyr-1) = rsnw_fall trcrn(nt_smice:nt_smice+nslyr-1) = rhos + trcrn(nt_rhos :nt_rhos +nslyr-1) = rhos endif end subroutine icepack_compute_tracers