diff --git a/.zenodo.json b/.zenodo.json index 06d7e588..f4d5dcab 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,19 +1,21 @@ { - "license": "other-open", - "description": "No description provided", + "license": "BSD-3-Clause", + "copyright": "Copyright 1998-2026 Triad National Security, LLC", + "description": "View detailed release notes at https://github.com/CICE-Consortium/Icepack/releases", "language": "eng", - "title": "CICE-Consortium/Icepack: Icepack m.n.p", + "title": "CICE-Consortium/Icepack: Icepack 1.5.3", "keywords": [ - "sea ice model, Icepack" + "sea ice model", + "Icepack" ], - "version": "m.n.p", + "version": "1.5.3", "upload_type": "software", "communities": [ { "identifier": "cice-consortium" } ], - "publication_date": "2019-06-20", + "publication_date": "2026-01-22", "creators": [ { "affiliation": "Los Alamos National Laboratory", @@ -31,6 +33,10 @@ "affiliation": "Environment and Climate Change Canada", "name": "Philippe Blain" }, + { + "affiliation": "National Center for Atmospheric Research", + "name": "David Clemens-Sewall" + }, { "affiliation": "National Oceanic and Atmospheric Administration", "name": "Anthony Craig" @@ -75,10 +81,18 @@ "affiliation": "Danish Meteorological Institute", "name": "Mads Ribergaard" }, + { + "affiliation": "Alfred-Wegener-Institut Helmholz-Zentrum fur Polar- und Meersforschung", + "name": "Lettie Roach" + }, { "affiliation": "Los Alamos National Laboratory", "name": "Andrew Roberts" }, + { + "affiliation": "Australian Earth-System Simulator", + "name": "Anton Steketee" + }, { "affiliation": "Los Alamos National Laboratory", "name": "Matthew Turner" @@ -86,9 +100,14 @@ { "affiliation": "Geophysical Fluid Dynamics Laboratory", "name": "Michael Winton" + }, + { + "affiliation": "National Aeronautics and Space Administration", + "name": "Bin Zhao" } ], "access_right": "open", + "repository_url": "https://github.com/CICE-Consortium/Icepack", "related_identifiers": [ { "identifier": "https://github.com/CICE-Consortium/Icepack/tree/Icepack1.0.0", diff --git a/COPYRIGHT.pdf b/COPYRIGHT.pdf new file mode 100644 index 00000000..6a8923c9 Binary files /dev/null and b/COPYRIGHT.pdf differ diff --git a/DistributionPolicy.pdf b/DistributionPolicy.pdf index 014c8881..cb8c17ac 100644 Binary files a/DistributionPolicy.pdf and b/DistributionPolicy.pdf differ diff --git a/LICENSE.pdf b/LICENSE.pdf index 18e26a09..5fea34da 100644 Binary files a/LICENSE.pdf and b/LICENSE.pdf differ diff --git a/columnphysics/icepack_algae.F90 b/columnphysics/icepack_algae.F90 index 7239edd1..a39b4a64 100644 --- a/columnphysics/icepack_algae.F90 +++ b/columnphysics/icepack_algae.F90 @@ -394,8 +394,7 @@ subroutine zbio (dt, & bio_index, & aicen, & vicen, vsnon, & - iphin, &! ntrcr - trcrn, aice_old, &!aice_old + iphin, trcrn, & flux_bion, flux_bio, & upNOn, upNHn, & upNO, upNH, & diff --git a/columnphysics/icepack_atmo.F90 b/columnphysics/icepack_atmo.F90 index f85b7794..2cee353f 100644 --- a/columnphysics/icepack_atmo.F90 +++ b/columnphysics/icepack_atmo.F90 @@ -507,8 +507,7 @@ end subroutine atmo_boundary_const ! ! changes: Andrew Roberts, NPS (RASM/CESM coupling and documentation) - subroutine neutral_drag_coeffs (apnd, hpnd, & - ipnd, & + subroutine neutral_drag_coeffs (apondn, & alvl, vlvl, & aice, vice, & vsno, aicen, & @@ -526,9 +525,7 @@ subroutine neutral_drag_coeffs (apnd, hpnd, & use icepack_tracers, only: tr_pond real (kind=dbl_kind), dimension (:), intent(in) :: & - apnd ,& ! melt pond fraction of sea ice - hpnd ,& ! mean melt pond depth over sea ice - ipnd ,& ! mean ice pond depth over sea ice in cat n + apondn ,& ! melt pond fraction of sea ice category alvl ,& ! level ice area fraction (of grid cell ?) vlvl ! level ice mean thickness @@ -666,7 +663,7 @@ subroutine neutral_drag_coeffs (apnd, hpnd, & if (tr_pond) then do n = 1,ncat ! area of pond per unit area of grid cell - apond = apond+apnd(n)*aicen(n) + apond = apond+apondn(n)*aicen(n) enddo endif diff --git a/columnphysics/icepack_brine.F90 b/columnphysics/icepack_brine.F90 index f4738a4d..1cb937fd 100644 --- a/columnphysics/icepack_brine.F90 +++ b/columnphysics/icepack_brine.F90 @@ -9,8 +9,8 @@ module icepack_brine use icepack_kinds use icepack_parameters, only: p01, p001, p5, c0, c1, c2, c1p5, puny, p25 use icepack_parameters, only: gravit, rhoi, rhow, rhos, depressT - use icepack_parameters, only: salt_loss, min_salin, rhosi - use icepack_parameters, only: dts_b, l_sk + use icepack_parameters, only: min_salin, rhosi + use icepack_parameters, only: l_sk use icepack_tracers, only: nilyr, nblyr, ntrcr, nt_qice, nt_sice use icepack_tracers, only: nt_Tsfc use icepack_zbgc_shared, only: k_o, exp_h, Dm, Ra_c, viscos_dynamic, thinS @@ -28,8 +28,7 @@ module icepack_brine compute_microS_mushy, & update_hbrine, & calculate_drho, & - icepack_init_hbrine, & - icepack_init_zsalinity ! deprecated + icepack_init_hbrine real (kind=dbl_kind), parameter :: & maxhbr = 1.25_dbl_kind , & ! brine overflows if hbr > maxhbr*hin @@ -51,7 +50,7 @@ module icepack_brine !======================================================================= ! Computes the top and bottom brine boundary changes for flushing -! works for zsalinity and tr_salinity +! works for tr_salinity ! ! NOTE: In this subroutine, trcrn(nt_fbri) is the volume fraction of ice with ! dynamic salinity or the height ratio = hbr/vicen*aicen, where hbr is the @@ -680,7 +679,7 @@ subroutine icepack_init_hbrine(bgrid_out, igrid_out, cgrid_out, & ! Calculate bio gridn: 0 to 1 corresponds to ice top to bottom !----------------------------------------------------------------- - bgrid(:) = c0 ! zsalinity grid points + bgrid(:) = c0 ! biology nondimensional vertical grid points bgrid(nblyr+2) = c1 ! bottom value igrid(:) = c0 ! bgc interface grid points igrid(1) = c0 ! ice top @@ -738,36 +737,6 @@ subroutine icepack_init_hbrine(bgrid_out, igrid_out, cgrid_out, & end subroutine icepack_init_hbrine -!======================================================================= -!autodocument_start icepack_init_zsalinity -! **DEPRECATED**, all code removed -! Interface provided for backwards compatibility - - subroutine icepack_init_zsalinity(Rayleigh_criteria, & - Rayleigh_real, trcrn_bgc, sss) - - logical (kind=log_kind), intent(inout) :: & - Rayleigh_criteria - - real (kind=dbl_kind), intent(inout):: & - Rayleigh_real - - real (kind=dbl_kind), intent(in):: & - sss - - real (kind=dbl_kind), dimension(:,:), intent(inout):: & - trcrn_bgc ! bgc subset of trcrn - -!autodocument_end - - ! local variables - - character(len=*),parameter :: subname='(icepack_init_zsalinity)' - - call icepack_warnings_add(subname//' DEPRECATED, do not use') -! call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - - end subroutine icepack_init_zsalinity !======================================================================= end module icepack_brine diff --git a/columnphysics/icepack_flux.F90 b/columnphysics/icepack_flux.F90 index 27a9f0f8..d5578076 100644 --- a/columnphysics/icepack_flux.F90 +++ b/columnphysics/icepack_flux.F90 @@ -12,7 +12,7 @@ module icepack_flux use icepack_parameters, only: c1, emissivity, snwgrain use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted - use icepack_tracers, only: tr_iso + use icepack_tracers, only: tr_iso, tr_pond implicit none private @@ -43,6 +43,8 @@ subroutine merge_fluxes (aicen, & fhocnn, fswthrun, & fswthrun_vdr, fswthrun_vdf,& fswthrun_idr, fswthrun_idf,& + fswthrun_uvrdr, fswthrun_uvrdf,& + fswthrun_pardr, fswthrun_pardf,& strairxT, strairyT, & Cdn_atm_ratio, & fsurf, fcondtop, & @@ -56,6 +58,8 @@ subroutine merge_fluxes (aicen, & fhocn, fswthru, & fswthru_vdr, fswthru_vdf,& fswthru_idr, fswthru_idf,& + fswthru_uvrdr, fswthru_uvrdf,& + fswthru_pardr, fswthru_pardf,& melttn, meltsn, meltbn, congeln, snoicen, & meltt, melts, & meltb, dsnow, dsnown,& @@ -64,12 +68,18 @@ subroutine merge_fluxes (aicen, & Uref, Urefn, & Qref_iso, Qrefn_iso, & fiso_ocn, fiso_ocnn, & - fiso_evap, fiso_evapn) - - ! single category fluxes + fiso_evap, fiso_evapn,& + dpnd_flush, dpnd_flushn, & + dpnd_expon, dpnd_exponn, & + dpnd_freebd, dpnd_freebdn, & + dpnd_initial, dpnd_initialn, & + dpnd_dlid, dpnd_dlidn) + + ! concentration is aicen_init in call to subroutine real (kind=dbl_kind), intent(in) :: & aicen ! concentration of ice + ! single category fluxes real (kind=dbl_kind), optional, intent(in) :: & flw , & ! downward longwave flux (W/m**2) strairxn, & ! air/ice zonal strss, (N/m**2) @@ -98,10 +108,19 @@ subroutine merge_fluxes (aicen, & dsnown , & ! change in snow depth (m) congeln , & ! congelation ice growth (m) snoicen , & ! snow-ice growth (m) + dpnd_flushn , & ! pond flushing rate due to ice permeability (m/step) + dpnd_exponn , & ! exponential pond drainage rate (m/step) + dpnd_freebdn, & ! pond drainage rate due to freeboard constraint (m/step) + dpnd_initialn,& ! runoff rate due to rfrac (m/step) + dpnd_dlidn , & ! pond loss/gain due to ice lid (m/step) fswthrun_vdr, & ! vis dir sw radiation through ice bot (W/m**2) fswthrun_vdf, & ! vis dif sw radiation through ice bot (W/m**2) fswthrun_idr, & ! nir dir sw radiation through ice bot (W/m**2) fswthrun_idf, & ! nir dif sw radiation through ice bot (W/m**2) + fswthrun_uvrdr, & ! < 400nm uv dir sw radiation through ice bot (W/m**2) + fswthrun_uvrdf, & ! < 400nm uv dif sw radiation through ice bot (W/m**2) + fswthrun_pardr, & ! 400-700nm par dir sw radiation through ice bot (W/m**2) + fswthrun_pardf, & ! 400-700nm par dif sw radiation through ice bot (W/m**2) Urefn ! air speed reference level (m/s) ! cumulative fluxes @@ -131,10 +150,19 @@ subroutine merge_fluxes (aicen, & meltsliq, & ! mass of snow melt (kg/m^2) congel , & ! congelation ice growth (m) snoice , & ! snow-ice growth (m) + dpnd_flush , & ! pond flushing rate due to ice permeability (m/step) + dpnd_expon , & ! exponential pond drainage rate (m/step) + dpnd_freebd, & ! pond drainage rate due to freeboard constraint (m/step) + dpnd_initial,& ! runoff rate due to rfrac (m/step) + dpnd_dlid , & ! pond loss/gain (+/-) to ice lid freezing/melting (m/step) fswthru_vdr, & ! vis dir sw radiation through ice bot (W/m**2) fswthru_vdf, & ! vis dif sw radiation through ice bot (W/m**2) fswthru_idr, & ! nir dir sw radiation through ice bot (W/m**2) fswthru_idf, & ! nir dif sw radiation through ice bot (W/m**2) + fswthru_uvrdr, & ! < 400nm uv dir sw radiation through ice bot (W/m**2) + fswthru_uvrdf, & ! < 400nm uv dif sw radiation through ice bot (W/m**2) + fswthru_pardr, & ! 400-700nm par dir sw radiation through ice bot (W/m**2) + fswthru_pardf, & ! 400-700nm par dif sw radiation through ice bot (W/m**2) dsnow, & ! change in snow depth (m) Uref ! air speed reference level (m/s) @@ -228,6 +256,15 @@ subroutine merge_fluxes (aicen, & if (present(fswthrun_idf) .and. present(fswthru_idf)) & fswthru_idf = fswthru_idf + fswthrun_idf * aicen + if (present(fswthrun_uvrdr) .and. present(fswthru_uvrdr)) & + fswthru_uvrdr = fswthru_uvrdr + fswthrun_uvrdr * aicen + if (present(fswthrun_uvrdf) .and. present(fswthru_uvrdf)) & + fswthru_uvrdf = fswthru_uvrdf + fswthrun_uvrdf * aicen + if (present(fswthrun_pardr) .and. present(fswthru_pardr)) & + fswthru_pardr = fswthru_pardr + fswthrun_pardr * aicen + if (present(fswthrun_pardf) .and. present(fswthru_pardf)) & + fswthru_pardf = fswthru_pardf + fswthrun_pardf * aicen + ! ice/snow thickness if (present(melttn) .and. present(meltt)) & @@ -247,6 +284,19 @@ subroutine merge_fluxes (aicen, & congel = congel + congeln * aicen if (present(snoicen) .and. present(snoice)) & snoice = snoice + snoicen * aicen + ! Meltwater fluxes + if (tr_pond) then + if (present(dpnd_flushn) .and. present(dpnd_flush)) & + dpnd_flush = dpnd_flush + dpnd_flushn * aicen + if (present(dpnd_exponn) .and. present(dpnd_expon)) & + dpnd_expon = dpnd_expon + dpnd_exponn * aicen + if (present(dpnd_freebdn) .and. present(dpnd_freebd)) & + dpnd_freebd = dpnd_freebd + dpnd_freebdn * aicen + if (present(dpnd_initialn).and. present(dpnd_initial)) & + dpnd_initial = dpnd_initial + dpnd_initialn * aicen + if (present(dpnd_dlidn) .and. present(dpnd_dlid)) & + dpnd_dlid = dpnd_dlid + dpnd_dlidn * aicen + endif end subroutine merge_fluxes diff --git a/columnphysics/icepack_fsd.F90 b/columnphysics/icepack_fsd.F90 index 896a422d..9b0f2e1f 100644 --- a/columnphysics/icepack_fsd.F90 +++ b/columnphysics/icepack_fsd.F90 @@ -180,7 +180,7 @@ subroutine icepack_init_fsd_bounds( & floe_area_c (nfsd), & ! fsd area at bin centre (m^2) floe_area_binwidth (nfsd), & ! floe area bin width (m^2) floe_binwidth (nfsd), & ! floe bin width (m) - c_fsd_range (nfsd), & ! + c_fsd_range (nfsd), & ! iweld (nfsd, nfsd), & ! fsd categories that can weld stat=ierr) if (ierr/=0) then @@ -620,7 +620,6 @@ subroutine fsd_add_new_ice (n, & wave_sig_ht, & wave_spectrum, & wavefreq, & - dwavefreq, & d_afsd_latg, & d_afsd_newi, & afsdn, aicen_init, & @@ -640,8 +639,7 @@ subroutine fsd_add_new_ice (n, & ! power spectral density of surface elevation, E(f) (units m^2 s) real(kind=dbl_kind), dimension(:), intent(in) :: & - wavefreq , & ! wave frequencies (s^-1) - dwavefreq ! wave frequency bin widths (s^-1) + wavefreq ! wave frequencies (s^-1) real (kind=dbl_kind), dimension(:), intent(in) :: & d_an_latg , & ! change in aicen due to lateral growth @@ -747,8 +745,7 @@ subroutine fsd_add_new_ice (n, & if (wave_spec) then if (wave_sig_ht > puny) then call wave_dep_growth (wave_spectrum, wave_sig_ht, & - wavefreq, dwavefreq, & - new_size) + wavefreq, new_size) if (icepack_warnings_aborted(subname)) return end if @@ -775,8 +772,7 @@ subroutine fsd_add_new_ice (n, & if (wave_spec) then if (wave_sig_ht > puny) then call wave_dep_growth (wave_spectrum, wave_sig_ht, & - wavefreq, dwavefreq, & - new_size) + wavefreq, new_size) if (icepack_warnings_aborted(subname)) return end if @@ -817,8 +813,7 @@ end subroutine fsd_add_new_ice ! authors: Lettie Roach, NIWA/VUW ! subroutine wave_dep_growth (local_wave_spec, wave_height, & - wavefreq, dwavefreq, & - new_size) + wavefreq, new_size) real (kind=dbl_kind), dimension(:), intent(in) :: & local_wave_spec ! ocean surface wave spectrum as a function of frequency @@ -826,11 +821,10 @@ subroutine wave_dep_growth (local_wave_spec, wave_height, & ! dimension set in ice_forcing real(kind=dbl_kind), dimension(:), intent(in) :: & - wavefreq, & ! wave frequencies (s^-1) - dwavefreq ! wave frequency bin widths (s^-1) + wavefreq ! wave frequencies (s^-1) - real(kind=dbl_kind), intent(in), optional :: & - wave_height ! significant wave height (m) + real(kind=dbl_kind), intent(in) :: & + wave_height ! significant wave height (m) integer (kind=int_kind), intent(out) :: & new_size ! index of floe size category in which new floes will grow @@ -847,11 +841,7 @@ subroutine wave_dep_growth (local_wave_spec, wave_height, & integer (kind=int_kind) :: k - if (present(wave_height)) then - w_amp = p5 * wave_height ! amplitude is 1/2 sig wave hight - else - w_amp = c2* SQRT(SUM(local_wave_spec*dwavefreq)) ! sig wave amplitude - endif + w_amp = p5 * wave_height ! amplitude is 1/2 sig wave height f_peak = wavefreq(MAXLOC(local_wave_spec, DIM=1)) ! peak frequency ! tensile failure diff --git a/columnphysics/icepack_intfc.F90 b/columnphysics/icepack_intfc.F90 index 2e96a7a9..a1eb4f65 100644 --- a/columnphysics/icepack_intfc.F90 +++ b/columnphysics/icepack_intfc.F90 @@ -1,17 +1,17 @@ !======================================================================= -! Copyright (c) 2024, Triad National Security, LLC +! Copyright 1998-2026 Triad National Security, LLC ! All rights reserved. ! -! Copyright 2024. Triad National Security, LLC. This software was -! produced under U.S. Government contract DE-AC52-06NA25396 for Los -! Alamos National Laboratory (LANL), which is operated by Triad -! National Security, LLC for the U.S. Department of Energy. The U.S. -! Government has rights to use, reproduce, and distribute this software. -! NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC MAKES ANY -! WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF -! THIS SOFTWARE. If software is modified to produce derivative works, -! such modified software should be clearly marked, so as not to confuse -! it with the version available from LANL. +! This program was produced under U.S. Government contract 89233218CNA000001 +! for Los Alamos National Laboratory (LANL), which is operated by Triad +! National Security, LLC for the U.S. Department of Energy/National Nuclear +! Security Administration. All rights in the program are reserved by Triad +! National Security, LLC, and the U.S. Department of Energy/National Nuclear +! Security Administration. The Government is granted for itself and others +! acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +! license in this material to reproduce, prepare. derivative works, +! distribute copies to the public, perform publicly and display publicly, +! and to permit others to do so. ! ! The full license and distribution policy are available from ! https://github.com/CICE-Consortium @@ -92,7 +92,6 @@ module icepack_intfc use icepack_shortwave, only: icepack_step_radiation use icepack_brine, only: icepack_init_hbrine - use icepack_brine, only: icepack_init_zsalinity ! deprecated use icepack_zbgc , only: icepack_init_bgc use icepack_zbgc , only: icepack_init_zbgc diff --git a/columnphysics/icepack_itd.F90 b/columnphysics/icepack_itd.F90 index 013373ad..8802a943 100644 --- a/columnphysics/icepack_itd.F90 +++ b/columnphysics/icepack_itd.F90 @@ -32,9 +32,10 @@ module icepack_itd use icepack_tracers, only: ncat, nilyr, nslyr, nblyr, ntrcr, nbtrcr, n_aero 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, bio_index + use icepack_tracers, only: tr_pond, tr_pond_lvl, nt_alvl use icepack_tracers, only: n_iso, tr_iso, nt_smice, nt_rsnw, nt_rhos, nt_sice use icepack_tracers, only: icepack_compute_tracers - use icepack_parameters, only: skl_bgc, z_tracers, hi_min + use icepack_parameters, only: skl_bgc, z_tracers, hi_min, itd_area_min, itd_mass_min use icepack_parameters, only: kcatbound, kitd, saltflux_option, snwgrain, snwredist use icepack_therm_shared, only: Tmin use icepack_warnings, only: warnstr, icepack_warnings_add @@ -295,28 +296,36 @@ end subroutine rebin subroutine reduce_area (hin_max, & aicen, vicen, & - aicen_init,vicen_init) + aicen_init,vicen_init, & + dpnd_melt, trcrn) real (kind=dbl_kind), intent(in) :: & hin_max ! lowest category boundary real (kind=dbl_kind), intent(inout) :: & aicen , & ! concentration of ice - vicen ! volume per unit area of ice (m) + vicen , & ! volume per unit area of ice (m) + dpnd_melt ! pond 'drainage' due to ice melting (m / step) real (kind=dbl_kind), intent(in) :: & aicen_init, & ! old ice area for category 1 (m) vicen_init ! old ice volume for category 1 (m) + real (kind=dbl_kind), dimension (:,:), intent(in) :: & + trcrn ! ice tracers + ! local variables real (kind=dbl_kind) :: & hi0 , & ! initial hi hi1 , & ! current hi - dhi ! hi1 - hi0 + dhi , & ! hi1 - hi0 + da ! total change in area complete within this subroutine character(len=*),parameter :: subname='(reduce_area)' + da = aicen ! store value of aicen at start of the subroutine + hi0 = c0 if (aicen_init > c0) & hi0 = vicen_init / aicen_init @@ -339,6 +348,15 @@ subroutine reduce_area (hin_max, & endif endif + da = da - aicen ! -1*change in fractional area over the subroutine + if (tr_pond) then + if (tr_pond_lvl) then + dpnd_melt = da*trcrn(nt_apnd,1)*trcrn(nt_hpnd,1)*trcrn(nt_alvl,1) + else + dpnd_melt = da*trcrn(nt_apnd,1)*trcrn(nt_hpnd,1) + endif + endif + end subroutine reduce_area !======================================================================= @@ -416,7 +434,6 @@ subroutine shift_ice (trcr_depend, & worka, workb real (kind=dbl_kind), dimension(ncat) :: aicen_init - real (kind=dbl_kind), dimension(ncat) :: vicen_init real (kind=dbl_kind), dimension(ncat) :: vsnon_init character(len=*),parameter :: subname='(shift_ice)' @@ -426,7 +443,6 @@ subroutine shift_ice (trcr_depend, & !----------------------------------------------------------------- aicen_init(:) = aicen(:) - vicen_init(:) = vicen(:) vsnon_init(:) = vsnon(:) !----------------------------------------------------------------- @@ -1058,6 +1074,10 @@ subroutine zap_small_areas (dt, & n, k, it, & !counting indices blevels + logical (kind=log_kind) :: & + zap_residual, & + zap_category(ncat) + real (kind=dbl_kind) :: xtmp, sicen ! temporary variables real (kind=dbl_kind) :: dvssl, dvint ! temporary variables real (kind=dbl_kind) , dimension (1):: trcr_skl @@ -1065,6 +1085,22 @@ subroutine zap_small_areas (dt, & character(len=*),parameter :: subname='(zap_small_areas)' + !----------------------------------------------------------------- + ! Flag categories with very small areas and residual ice + !----------------------------------------------------------------- + + zap_category(:) = .false. + do n = 1, ncat + if ( abs(aicen(n)) <= puny .and. & + (abs(aicen(n)) /= c0 .or. abs(vicen(n)) /= c0 .or. abs(vsnon(n)) /= c0)) then + zap_category(n) = .true. + endif + enddo + + zap_residual = .false. + if (aice < max(itd_area_min, puny) .or. & + aice*rhoi < max(itd_mass_min, puny)) zap_residual = .true. ! all categories + !----------------------------------------------------------------- ! I. Zap categories with very small areas. !----------------------------------------------------------------- @@ -1079,8 +1115,7 @@ subroutine zap_small_areas (dt, & call icepack_warnings_setabort(.true.,__FILE__,__LINE__) call icepack_warnings_add(subname//' Zap ice: negative ice area') return - elseif (abs(aicen(n)) /= c0 .and. & - abs(aicen(n)) <= puny) then + elseif (zap_category(n) .or. zap_residual) then !----------------------------------------------------------------- ! Account for tracers important for conservation diff --git a/columnphysics/icepack_mechred.F90 b/columnphysics/icepack_mechred.F90 index 70766cc6..72263df9 100644 --- a/columnphysics/icepack_mechred.F90 +++ b/columnphysics/icepack_mechred.F90 @@ -42,7 +42,8 @@ module icepack_mechred use icepack_parameters, only: kstrength, krdg_partic, krdg_redist, mu_rdg use icepack_parameters, only: conserv_check, z_tracers use icepack_tracers, only: ncat, nilyr, nslyr, nblyr, n_aero - use icepack_tracers, only: tr_pond_topo, tr_aero, tr_iso, tr_brine, ntrcr, nbtrcr + use icepack_tracers, only: tr_aero, tr_iso, tr_brine, ntrcr, nbtrcr + use icepack_tracers, only: tr_pond_lvl, tr_pond_topo, tr_pond_sealvl use icepack_tracers, only: nt_qice, nt_qsno, nt_fbri, nt_sice use icepack_tracers, only: nt_alvl, nt_vlvl, nt_aero, nt_isosno, nt_isoice use icepack_tracers, only: nt_apnd, nt_hpnd @@ -108,7 +109,7 @@ subroutine ridge_ice (dt, ndtd, & dardg1ndt, dardg2ndt, & dvirdgndt, Tf, & araftn, vraftn, & - closing ) + closing, dpnd_ridge) integer (kind=int_kind), intent(in) :: & ndtd ! number of dynamics subcycles @@ -165,7 +166,8 @@ subroutine ridge_ice (dt, ndtd, & closing , & ! rate of closing due to divergence/shear (1/s) fpond , & ! fresh water flux to ponds (kg/m^2/s) fresh , & ! fresh water flux to ocean (kg/m^2/s) - fhocn ! net heat flux to ocean (W/m^2) + fhocn , & ! net heat flux to ocean (W/m^2) + dpnd_ridge ! pond drainage due to ridging (m avg. over cell) real (kind=dbl_kind), dimension(:), intent(inout), optional :: & dardg1ndt , & ! rate of fractional area loss by ridging ice (1/s) @@ -202,7 +204,8 @@ subroutine ridge_ice (dt, ndtd, & aksum , & ! ratio of area removed to area ridged msnow_mlt , & ! mass of snow added to ocean (kg m-2) esnow_mlt , & ! energy needed to melt snow in ocean (J m-2) - mpond , & ! mass of pond added to ocean (kg m-2) + mpond , & ! thickness of pond water (avg. over grid cell) lost + ! due to ridging (m) closing_net, & ! net rate at which area is removed (1/s) ! (ridging ice area - area of new ridges) / dt divu_adv , & ! divu as implied by transport scheme (1/s) @@ -602,9 +605,11 @@ subroutine ridge_ice (dt, ndtd, & enddo endif endif + ! diagnostic for all non-topo pond schemes, which are virtual if (present(fpond)) then fpond = fpond - mpond ! units change later endif + if (present(dpnd_ridge)) dpnd_ridge = mpond !----------------------------------------------------------------- ! Check for fractional ice area > 1. @@ -1143,7 +1148,8 @@ subroutine ridge_shift (dt, hin_max, & real (kind=dbl_kind), intent(inout) :: & msnow_mlt , & ! mass of snow added to ocean (kg m-2) esnow_mlt , & ! energy needed to melt snow in ocean (J m-2) - mpond ! mass of pond added to ocean (kg m-2) + mpond ! thickness of pond water, averaged over entire grid + ! cell area, lost to ridging (m) real (kind=dbl_kind), dimension(:), intent(inout) :: & maero ! aerosol mass added to ocean (kg m-2) @@ -1389,7 +1395,12 @@ subroutine ridge_shift (dt, hin_max, & enddo endif - if (tr_pond_topo) then + ! diagnostic for all non-topo pond schemes, which are virtual + if (tr_pond_lvl) then + mpond = mpond + ardg1n * trcrn(nt_apnd,n) & + * trcrn(nt_hpnd,n) & + * trcrn(nt_alvl,n) + elseif (tr_pond_topo .or. tr_pond_sealvl) then mpond = mpond + ardg1n * trcrn(nt_apnd,n) & * trcrn(nt_hpnd,n) endif @@ -1739,9 +1750,9 @@ subroutine icepack_step_ridge(dt, ndtd, & dvirdgndt, & araftn, vraftn, & aice, fsalt, & - first_ice, fzsal, & + first_ice, & flux_bio, closing, & - Tf, & + Tf, dpnd_ridge, & docleanup, dorebin) real (kind=dbl_kind), intent(in) :: & @@ -1781,9 +1792,6 @@ subroutine icepack_step_ridge(dt, ndtd, & fsalt , & ! salt flux to ocean (kg/m^2/s) fhocn ! net heat flux to ocean (W/m^2) - real (kind=dbl_kind), intent(inout), optional :: & - fzsal ! zsalinity flux to ocean(kg/m^2/s) (deprecated) - real (kind=dbl_kind), intent(inout), optional :: & closing ! rate of closing due to divergence/shear (1/s) @@ -1817,6 +1825,9 @@ subroutine icepack_step_ridge(dt, ndtd, & logical (kind=log_kind), dimension(:), intent(inout) :: & first_ice ! true until ice forms + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_ridge ! pond drainage due to ridging + logical (kind=log_kind), intent(in), optional :: & docleanup, & ! if false, do not call cleanup_itd (default true) dorebin ! if false, do not call rebin in cleanup_itd (default true) @@ -1893,7 +1904,7 @@ subroutine icepack_step_ridge(dt, ndtd, & dardg1ndt, dardg2ndt, & dvirdgndt, Tf, & araftn, vraftn, & - closing ) + closing, dpnd_ridge ) if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- diff --git a/columnphysics/icepack_meltpond_lvl.F90 b/columnphysics/icepack_meltpond_lvl.F90 index 90d5f684..75877786 100644 --- a/columnphysics/icepack_meltpond_lvl.F90 +++ b/columnphysics/icepack_meltpond_lvl.F90 @@ -42,7 +42,11 @@ subroutine compute_ponds_lvl(dt, & qicen, sicen, & Tsfcn, alvl, & apnd, hpnd, ipnd, & - meltsliqn) + meltsliqn, & + dpnd_freebdn, & + dpnd_initialn, & + dpnd_dlidn, & + dpnd_flushn) real (kind=dbl_kind), intent(in) :: & dt ! time step (s) @@ -62,7 +66,11 @@ subroutine compute_ponds_lvl(dt, & meltsliqn ! liquid contribution to meltponds in dt (kg/m^2) real (kind=dbl_kind), intent(inout) :: & - apnd, hpnd, ipnd + apnd, hpnd, ipnd, & + dpnd_freebdn, & ! pond drainage rate due to freeboard constraint (m/step) + dpnd_initialn, & ! runoff rate due to rfrac (m/step) + dpnd_dlidn, & ! pond loss/gain due to ice lid (m/step) + dpnd_flushn ! pond flushing rate due to ice permeability (m/s) real (kind=dbl_kind), dimension (:), intent(in) :: & qicen, & ! ice layer enthalpy (J m-3) @@ -77,7 +85,9 @@ subroutine compute_ponds_lvl(dt, & ! local temporary variables real (kind=dbl_kind) :: & - volpn ! pond volume per unit area (m) + volpn, & ! pond volume per unit area (m) + hpond_tmp, & ! local variable for hpond before flushing + dvn_temp ! local variable for change in volume due to rfrac real (kind=dbl_kind), dimension (nilyr) :: & Tmlt ! melting temperature (C) @@ -149,6 +159,13 @@ subroutine compute_ponds_lvl(dt, & + melts*rhos & + frain* dt)*aicen endif + ! Track meltwater runoff fraction. Here dvn is volume of + ! meltwater (m3/m2) captured over entire grid cell area. + ! Multiply by (1-rfrac)/rfrac to get loss over entire area. + ! Divide by aicen to get loss per unit category area + ! (for consistency with melttn, dpnd_freebdn, etc) + dpnd_initialn = dvn * (c1-rfrac) / (rfrac * aicen) + dvn_temp = dvn ! shrink pond volume under freezing conditions if (trim(frzpnd) == 'cesm') then @@ -188,6 +205,9 @@ subroutine compute_ponds_lvl(dt, & endif volpn = volpn + dvn + ! Track lost/gained meltwater per unit category area from pond + ! lid freezing/melting. Note sign flip relative to dvn convention + dpnd_dlidn = (dvn_temp - dvn) / aicen !----------------------------------------------------------- ! update pond area and depth @@ -206,21 +226,25 @@ subroutine compute_ponds_lvl(dt, & elseif (alvl_tmp*aicen > c10*puny) then ! new ponds apondn = min (sqrt(volpn/(pndaspect*aicen)), alvl_tmp) - hpondn = pndaspect * apondn + hpondn = pndaspect * apondn ! Possible loss of meltwater if apondn == alvl_tmp else ! melt water runs off deformed ice apondn = c0 - hpondn = c0 + hpondn = c0 ! Loss of meltwater for very deformed ice endif apondn = max(apondn, c0) ! limit pond depth to maintain nonnegative freeboard + hpond_tmp = hpondn hpondn = min(hpondn, ((rhow-rhoi)*hi - rhos*hs)/rhofresh) + dpnd_freebdn = (hpond_tmp - hpondn) * apondn ! fraction of grid cell covered by ponds apondn = apondn * aicen volpn = hpondn*apondn + ! note, this implies that if ponds fully drain or freeze their + ! depressions cease to exist and the lid ice also ceases to exist if (volpn <= c0) then volpn = c0 apondn = c0 @@ -250,6 +274,7 @@ subroutine compute_ponds_lvl(dt, & + 0.5*dvn/(pndaspect*apondn), alvl_tmp*aicen)) hpondn = c0 if (apondn > puny) hpondn = volpn/apondn + dpnd_flushn = -dvn/aicen endif endif diff --git a/columnphysics/icepack_meltpond_sealvl.F90 b/columnphysics/icepack_meltpond_sealvl.F90 new file mode 100644 index 00000000..cd463f7d --- /dev/null +++ b/columnphysics/icepack_meltpond_sealvl.F90 @@ -0,0 +1,479 @@ +!======================================================================= + +! sealvl meltpond parameterization +! +! This meltpond parameterization partitions pond volume into depth +! and area based on an assumed, subcategory elevation distribution +! (hypsometry) which permits pond bases to sit below sea level. +! Pond upper surfaces can be below sea level (e.g., when ponds initially +! form in the spring or after mechanical redistribution), but drainage +! processes will not lower pond surfaces below sea level (with the +! default parameter values). Currently, the only physical impacts +! of pond water are in the delta-Eddington radiation scheme. +! +! The sealvl meltpond parameterization was inspired by the level pond +! parameterization of Elizabeth Hunke, David Hebert, and Olivier +! Lecomte. Wherever possible, the code matches the level pond scheme +! (e.g., the pond lid refreezing calculations). +! +! authors David Clemens-Sewall (NCAR/NOAA) + + module icepack_meltpond_sealvl + + use icepack_kinds + use icepack_parameters, only: c0, c1, c2, c10, p01, p5, puny + use icepack_parameters, only: viscosity_dyn, rhoi, rhos, rhow + use icepack_parameters, only: Timelt, Tffresh, Lfresh, rhofresh + use icepack_parameters, only: gravit, depressT, rhofresh, kice + use icepack_parameters, only: rhosi, use_smliq_pnd + use icepack_parameters, only: ktherm, frzpnd, dpscale, hi_min + use icepack_parameters, only: pndhyps, pndfrbd, pndhead, apnd_sl + use icepack_parameters, only: pndaspect + use icepack_tracers, only: nilyr + use icepack_warnings, only: warnstr, icepack_warnings_add + use icepack_warnings, only: icepack_warnings_setabort + use icepack_warnings, only: icepack_warnings_aborted + + implicit none + + private + public :: compute_ponds_sealvl, & + pond_hypsometry, & + pond_height + +!======================================================================= + + contains + +!======================================================================= + + subroutine compute_ponds_sealvl( dt, & + meltt, melts, frain, & + Tair, fsurfn, Tsfcn, & + dhs, ffrac, & + aicen, vicen, vsnon, & + qicen, sicen, & + apnd, hpnd, ipnd, & + meltsliqn, & + dpnd_freebdn, & + dpnd_dlidn, dpnd_flushn) + + real (kind=dbl_kind), intent(in) :: & + dt ! time step (s) + + real (kind=dbl_kind), intent(in) :: & + Tsfcn, & ! surface temperature (C) + meltt, & ! top melt rate (m/s) + melts, & ! snow melt rate (m/s) + frain, & ! rainfall rate (kg/m2/s) + Tair, & ! air temperature (K) + fsurfn,& ! atm-ice surface heat flux (W/m2) + aicen, & ! ice area fraction + vicen, & ! ice volume (m) + vsnon, & ! snow volume (m) + meltsliqn ! liquid contribution to meltponds in dt (kg/m^2) + + real (kind=dbl_kind), intent(inout) :: & + apnd, hpnd, ipnd, & ! pond tracers + dpnd_freebdn, & ! pond drainage rate due to freeboard constraint (m/step) + dpnd_dlidn, & ! pond loss/gain due to ice lid (m/step) + dpnd_flushn ! pond flushing rate due to ice permeability (m/s) + + real (kind=dbl_kind), dimension (:), intent(in) :: & + qicen, & ! ice layer enthalpy (J m-3) + sicen ! salinity (ppt) + + real (kind=dbl_kind), intent(in) :: & + dhs ! depth difference for snow on sea ice and pond ice + + real (kind=dbl_kind), intent(out) :: & + ffrac ! fraction of fsurfn over pond used to melt ipond + + ! local temporary variables + + real (kind=dbl_kind) :: & + dhpond, & ! change in hpond (m) + dvn_temp ! local variable for change in volume due to rfrac + + real (kind=dbl_kind), dimension (nilyr) :: & + Tmlt ! melting temperature (C) + + real (kind=dbl_kind) :: & + hi , & ! ice thickness (m) + hs , & ! snow depth (m) + dTs , & ! surface temperature diff for freeze-up (C) + Tp , & ! pond freezing temperature (C) + Ts , & ! surface air temperature (C) + vpondn , & ! pond volume per category area (m) + dvpondn , & ! change in pond volume per category area (m) + hlid , & ! refrozen lid thickness + dhlid , & ! change in refrozen lid thickness + bdt , & ! 2 kice dT dt / (rhoi Lfresh) + hpsurf , & ! height of pond surface above mean ice base (m) + draft, pressure_head, perm, drain ! for permeability + + real (kind=dbl_kind), parameter :: & + Td = c2 , & ! temperature difference for freeze-up (C) + rexp = p01 ! pond contraction scaling + + character(len=*),parameter :: subname='(compute_ponds_sealvl)' + + !----------------------------------------------------------------- + ! Initialize + !----------------------------------------------------------------- + + vpondn = hpnd * apnd + ffrac = c0 + + !----------------------------------------------------------------- + ! Identify grid cells where ponds can be + !----------------------------------------------------------------- + + if (aicen > puny) then + + hi = vicen/aicen + hs = vsnon/aicen + + if (hi < hi_min) then + + !----------------------------------------------------------- + ! Remove ponds on thin ice + !----------------------------------------------------------- + dpnd_freebdn = vpondn + apnd = c0 + hpnd = c0 + vpondn = c0 + hlid = c0 + + else + + !----------------------------------------------------------- + ! update pond volume + !----------------------------------------------------------- + ! add melt water + if (use_smliq_pnd) then + dvpondn = (meltt*rhoi + meltsliqn)/rhofresh + else + dvpondn = (meltt*rhoi + melts*rhos + frain*dt)/rhofresh + endif + dvn_temp = dvpondn + + ! shrink pond volume under freezing conditions + if (trim(frzpnd) == 'cesm') then + Tp = Timelt - Td + dTs = max(Tp - Tsfcn,c0) + dvpondn = dvpondn - vpondn * (c1 - exp(rexp*dTs/Tp)) + + else + ! trim(frzpnd) == 'hlid' Stefan approximation + ! assumes pond is fresh (freezing temperature = 0 C) + ! and ice grows from existing pond ice + hlid = ipnd + if (dvpondn == c0) then ! freeze pond + Ts = Tair - Tffresh + if (Ts < c0) then + ! if (Ts < -c2) then ! as in meltpond_cesm + bdt = -c2*Ts*kice*dt/(rhoi*Lfresh) + dhlid = p5*sqrt(bdt) ! open water freezing + if (hlid > dhlid) dhlid = p5*bdt/hlid ! extant ice + dhlid = min(dhlid, hpnd*rhofresh/rhoi) + hlid = hlid + dhlid + else + dhlid = c0 ! to account for surface inversions + endif + else ! convert refrozen pond ice back to water + dhlid = max(fsurfn*dt / (rhoi*Lfresh), c0) ! > 0 + dhlid = -min(dhlid, hlid) ! < 0 + hlid = max(hlid + dhlid, c0) + if (hs - dhs < puny) then ! pond ice is snow-free + ! fraction of fsurfn over pond used to melt ipond + ffrac = c1 + if (fsurfn > puny) & + ffrac = min(-dhlid*rhoi*Lfresh/(dt*fsurfn), c1) + endif + endif + dvpondn = dvpondn - dhlid*apnd*rhoi/rhofresh + endif + + ! Track lost/gained meltwater per unit category area from + ! pond lid freezing/melting. Note sign flip relative to dvn + dpnd_dlidn = dvn_temp - dvpondn + + !----------------------------------------------------------- + ! update pond area and depth + !----------------------------------------------------------- + call pond_hypsometry(hpnd, apnd, dvpond=dvpondn, hin=hi) + if (icepack_warnings_aborted(subname)) return + + dhpond = c0 + ! limit pond depth to maintain nonnegative freeboard + if (trim(pndfrbd) == 'floor') then + dhpond = ((rhow-rhoi)*hi - rhos*hs)/rhofresh - hpnd + elseif (trim(pndfrbd) == 'category') then + if (apnd .gt. puny) & + dhpond = ((rhow-rhoi)*hi-rhos*hs)/(rhofresh*apnd) & + - hpnd + else + call icepack_warnings_add(subname// & + " invalid pndfrbd option" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + dhpond = min(dhpond, c0) ! strictly drainage + dpnd_freebdn = - dhpond * apnd + call pond_hypsometry(hpnd, apnd, dhpond=dhpond, hin=hi) + if (icepack_warnings_aborted(subname)) return + + ! clean up empty ponds. Note, this implies that if ponds + ! fully drain or freeze, the lid ice also ceases to exist + if (hpnd <= puny .or. apnd <= puny) then + apnd = c0 + hpnd = c0 + hlid = c0 + endif + + !----------------------------------------------------------- + ! drainage due to permeability (flushing) + ! setting dpscale = 0 turns this off + ! NOTE this uses the initial salinity and melting T profiles + !----------------------------------------------------------- + + if (ktherm /= 2 .and. hpnd > c0 .and. dpscale > puny) then + draft = (rhos*hs + rhoi*hi + rhofresh*hpnd*apnd)/rhow + call pond_height(apnd, hpnd, hi, hpsurf) + if (icepack_warnings_aborted(subname)) return + pressure_head = gravit * rhow * max(hpsurf - draft, c0) + Tmlt(:) = -sicen(:) * depressT + call brine_permeability(qicen, & + sicen, Tmlt, perm) + if (icepack_warnings_aborted(subname)) return + drain = perm*pressure_head*dt/(viscosity_dyn*hi)*dpscale + dhpond = -min(drain, hpnd) + dpnd_flushn = -dhpond * apnd + call pond_hypsometry(hpnd, apnd, dhpond=dhpond, hin=hi) + if (icepack_warnings_aborted(subname)) return + endif + endif ! hi < hi_min + + !----------------------------------------------------------- + ! Reload tracer array + !----------------------------------------------------------- + if (trim(frzpnd) == 'hlid') ipnd = hlid + + endif + + end subroutine compute_ponds_sealvl + +!======================================================================= + +! determine the liquid fraction of brine in the ice and the permeability + + subroutine brine_permeability(qicen, salin, Tmlt, perm) + + use icepack_therm_shared, only: calculate_Tin_from_qin + + real (kind=dbl_kind), dimension(:), intent(in) :: & + qicen, & ! enthalpy for each ice layer (J m-3) + salin, & ! salinity (ppt) + Tmlt ! melting temperature (C) + + real (kind=dbl_kind), intent(out) :: & + perm ! permeability (m^2) + + ! local variables + + real (kind=dbl_kind) :: & + Sbr ! brine salinity + + real (kind=dbl_kind), dimension(nilyr) :: & + Tin, & ! ice temperature (C) + phi ! liquid fraction + + integer (kind=int_kind) :: k + + character(len=*),parameter :: subname='(brine_permeability)' + + !----------------------------------------------------------------- + ! Compute ice temperatures from enthalpies using quadratic formula + !----------------------------------------------------------------- + + do k = 1,nilyr + Tin(k) = calculate_Tin_from_qin(qicen(k),Tmlt(k)) + enddo + + !----------------------------------------------------------------- + ! brine salinity and liquid fraction + !----------------------------------------------------------------- + + do k = 1,nilyr + Sbr = c1/(1.e-3_dbl_kind - depressT/Tin(k)) ! Notz thesis eq 3.6 + phi(k) = salin(k)/Sbr ! liquid fraction + if (phi(k) < 0.05) phi(k) = c0 ! impermeable + enddo + + !----------------------------------------------------------------- + ! permeability + !----------------------------------------------------------------- + + perm = 3.0e-8_dbl_kind * (minval(phi))**3 + + end subroutine brine_permeability + +!======================================================================= + +! compute the changes in pond area and depth + + subroutine pond_hypsometry(hpnd, apnd, dhpond, dvpond, hin) + + real (kind=dbl_kind), intent(inout) :: & + hpnd, & ! pond depth of ponded area tracer + apnd ! pond fractional area of category tracer + + real (kind=dbl_kind), intent(in), optional :: & + dvpond, & ! incoming change in pond volume per category area + dhpond, & ! incoming change in pond depth + hin ! category ice thickness + + ! local variables + + real (kind=dbl_kind) :: & + dv, & ! local variable for change in pond volume + vp, & ! local variable for pond volume per category area + pndasp ! pond aspect ratio + + character(len=*),parameter :: subname='(pond_hypsometry)' + + ! Behavior is undefined if dhpond and dvpond are both present + if (present(dhpond) .and. present(dvpond)) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname// & + " dhpond and dvpond cannot both be input" ) + return + endif + ! or both absent + if ((.not. present(dhpond)) .and. (.not. present(dvpond))) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname// & + " dhpond and dvpond cannot both be absent" ) + return + endif + ! Check that category ice thickness is present if needed + if ((trim(pndhyps) == 'sealevel') .and. (.not. present(hin))) then + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + call icepack_warnings_add(subname// & + " hin needed for sealevel ponds") + return + endif + + ! Get the change in volume + if (present(dvpond)) then + dv = dvpond + else ! compute change in volume from change in depth + dv = dhpond * apnd + endif + ! compute initial pond volume from area and depth + vp = apnd * hpnd + vp = vp + dv ! update pond volume + ! Compute pond area assuming that apond*pndaspect = hpond + if (vp <= puny) then + apnd = c0 + hpnd = c0 + else + if (trim(pndhyps) == 'sealevel') then + pndasp = calc_pndasp(hin) + elseif (trim(pndhyps) == 'fixed') then + pndasp = pndaspect + else + call icepack_warnings_add(subname// & + " unsupported pndhyps option" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + apnd = sqrt(vp/pndasp) + ! preserve pond volume if pond fills all available area + hpnd = c0 + if (apnd < c1) then + hpnd = apnd * pndasp + else + apnd = 1 ! ponds fill entire category + hpnd = vp ! conserve volume + endif + endif + + end subroutine pond_hypsometry + +!======================================================================= + +! compute the height of pond upper surface above mean base of ice + + subroutine pond_height(apond, hpnd, hin, hpsurf) + + real (kind=dbl_kind), intent(in) :: & + hin , & ! category mean ice thickness + apond , & ! pond area fraction of the category + hpnd ! mean pond depth (m) + + real (kind=dbl_kind), intent(out) :: & + hpsurf ! height of pond surface above base of the ice (m) + + ! local variables + real (kind=dbl_kind) :: & + pndasp ! pond aspect ratio + + character(len=*),parameter :: subname='(pond_height)' + + if (trim(pndhead) == 'perched') then + hpsurf = hin + hpnd + elseif (trim(pndhead) == 'hyps') then + if ((trim(pndhyps) == 'fixed') .or. & + (trim(pndhyps) == 'sealevel')) then + ! Applying a fixed aspect ratio to the ponds implicitly + ! assumes that the hypsometric curve has a constant slope + ! of double the aspect ratio. + ! If ponds occupy lowest elevations first. + if (trim(pndhyps) == 'sealevel') then + pndasp = calc_pndasp(hin) + else + pndasp = pndaspect + endif + if (apond < c1) then + hpsurf = hin - pndasp + c2*pndasp*apond + else ! ponds cover all available area + hpsurf = hin + hpnd + endif + else + call icepack_warnings_add(subname// & + " unsupported pndhyps option" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + else + call icepack_warnings_add(subname// & + " invalid pndhead option" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + + end subroutine pond_height + +!======================================================================= + + function calc_pndasp(hin) & + result(pndasp) + + real (kind=dbl_kind), intent(in) :: & + hin ! category mean ice thickness (m) + + real (kind=dbl_kind) :: & + pndasp ! pond aspect ratio + + character(len=*),parameter :: subname='(calc_pndasp)' + + ! Compute the pond aspect ratio for sea level ponds + pndasp = hin*(rhow - rhosi) / & + (rhofresh*apnd_sl**c2 - c2*rhow*apnd_sl + rhow) + + end function calc_pndasp + + end module icepack_meltpond_sealvl +!======================================================================= diff --git a/columnphysics/icepack_orbital.F90 b/columnphysics/icepack_orbital.F90 index a6a2bf40..8ebc0f23 100644 --- a/columnphysics/icepack_orbital.F90 +++ b/columnphysics/icepack_orbital.F90 @@ -172,7 +172,7 @@ subroutine compute_coszen (tlat, tlon, & nextsw_cday ! julian day of next shortwave calculation character (len=char_len), intent(in), optional :: & - calendar_type ! differentiates Gregorian from other calendars + calendar_type ! differentiates proleptic_gregorian from other calendars ! local variables @@ -196,7 +196,8 @@ subroutine compute_coszen (tlat, tlon, & endif endif - if (calendar_type == "GREGORIAN") then + if (calendar_type == "GREGORIAN" .or. & + calendar_type == "proleptic_gregorian") then ydayp1 = min(nextsw_cday, real(days_per_year,kind=dbl_kind)) else ydayp1 = nextsw_cday diff --git a/columnphysics/icepack_parameters.F90 b/columnphysics/icepack_parameters.F90 index 325be6a0..fe6ce051 100644 --- a/columnphysics/icepack_parameters.F90 +++ b/columnphysics/icepack_parameters.F90 @@ -126,10 +126,8 @@ module icepack_parameters ! phi_init, dSin0_frazil are for mushy thermo phi_init = 0.75_dbl_kind ,&! initial liquid fraction of frazil min_salin = p1 ,&! threshold for brine pocket treatment - salt_loss = 0.4_dbl_kind ,&! fraction of salt retained in zsalinity Tliquidus_max = c0 ,&! maximum liquidus temperature of mush (C) dSin0_frazil = c3 ,&! bulk salinity reduction of newly formed frazil - dts_b = 50._dbl_kind ,&! zsalinity timestep ustar_min = 0.005_dbl_kind ,&! minimum friction velocity for ocean heat flux (m/s) hi_min = p01 ,&! minimum ice thickness allowed (m) for thermo ! mushy thermo @@ -155,8 +153,9 @@ module icepack_parameters calc_Tsfc = .true. ,&! if true, calculate surface temperature ! if false, Tsfc is computed elsewhere and ! atmos-ice fluxes are provided to CICE + semi_implicit_Tsfc = .false. ,&! surface temperature coupling option + vapor_flux_correction = .false. ,&! compute mass/enthalpy correction for evaporation/sublimation update_ocn_f = .false. ,&! include fresh water and salt fluxes for frazil - solve_zsal = .false. ,&! if true, update salinity profile from solve_S_dt modal_aero = .false. ,&! if true, use modal aerosal optical properties ! only for use with tr_aero or tr_zaero conserv_check = .false. ! if true, do conservations checks and abort @@ -236,6 +235,12 @@ module icepack_parameters character (len=char_len), public :: & snw_ssp_table = 'test' ! lookup table: 'snicar' or 'test' + ! Parameters for the impact of pond depth on shortwave + real (kind=dbl_kind), public :: & + hpmin = 0.005_dbl_kind, & ! minimum allowed melt pond depth (m) + hp0 = 0.200_dbl_kind ! pond depth below which transition to bare ice + + !----------------------------------------------------------------------- ! Parameters for dynamics, including ridging and strength !----------------------------------------------------------------------- @@ -249,17 +254,19 @@ module icepack_parameters ! 1 for exponential redistribution function real (kind=dbl_kind), public :: & - Cf = 17._dbl_kind ,&! ratio of ridging work to PE change in ridging - Pstar = 2.75e4_dbl_kind ,&! constant in Hibler strength formula - ! (kstrength = 0) - Cstar = 20._dbl_kind ,&! constant in Hibler strength formula - ! (kstrength = 0) - dragio = 0.00536_dbl_kind ,&! ice-ocn drag coefficient + itd_area_min = 1.e-11_dbl_kind ,&! zap residual ice below a minimum area + itd_mass_min = 1.e-10_dbl_kind ,&! zap residual ice below a minimum mass + Cf = 17._dbl_kind ,&! ratio of ridging work to PE change in ridging + Pstar = 2.75e4_dbl_kind ,&! constant in Hibler strength formula + ! (kstrength = 0) + Cstar = 20._dbl_kind ,&! constant in Hibler strength formula + ! (kstrength = 0) + dragio = 0.00536_dbl_kind ,&! ice-ocn drag coefficient thickness_ocn_layer1 = 2.0_dbl_kind,&! thickness of first ocean level (m) - iceruf_ocn = 0.03_dbl_kind ,&! under-ice roughness (m) - gravit = 9.80616_dbl_kind ,&! gravitational acceleration (m/s^2) - mu_rdg = 3.0_dbl_kind ! e-folding scale of ridged ice, krdg_partic=1 (m^0.5) - ! (krdg_redist = 1) + iceruf_ocn = 0.03_dbl_kind ,&! under-ice roughness (m) + gravit = 9.80616_dbl_kind ,&! gravitational acceleration (m/s^2) + mu_rdg = 3.0_dbl_kind ! e-folding scale of ridged ice, krdg_partic=1 (m^0.5) + ! (krdg_redist = 1) logical (kind=log_kind), public :: & calc_dragio = .false. ! if true, calculate dragio from iceruf_ocn and thickness_ocn_layer1 @@ -333,18 +340,27 @@ module icepack_parameters !----------------------------------------------------------------------- real (kind=dbl_kind), public :: & - hs0 = 0.03_dbl_kind ! snow depth for transition to bare sea ice (m) - - ! level-ice ponds - character (len=char_len), public :: & - frzpnd = 'cesm' ! pond refreezing parameterization + hs0 = 0.03_dbl_kind, & ! snow depth for transition to bare sea ice (m) + hs1 = 0.03_dbl_kind ! snow depth for transition to bare pond ice (m) real (kind=dbl_kind), public :: & dpscale = 0.001_dbl_kind,& ! alter e-folding time scale for flushing (ktherm=1) rfracmin = 0.15_dbl_kind, & ! minimum retained fraction of meltwater rfracmax = 0.85_dbl_kind, & ! maximum retained fraction of meltwater - pndaspect = 0.8_dbl_kind, & ! ratio of pond depth to area fraction - hs1 = 0.03_dbl_kind ! snow depth for transition to bare pond ice (m) + pndaspect = 0.8_dbl_kind ! ratio of pond depth to area fraction + + character (len=char_len), public :: & + frzpnd = 'cesm' ! pond refreezing parameterization + + ! sealvl ponds + real (kind=dbl_kind), public :: & + apnd_sl = 0.27_dbl_kind ! equilibrium pond fraction for sea level parameterization + + character (len=char_len), public :: & + pndhyps = 'sealevel' , & ! pond hypsometry option + pndfrbd = 'floor' , & ! over what domain to calculate freeboard constraint + pndhead = 'perched' , & ! geometry for computing pond pressure head + pndmacr = 'lambda' ! driving force for macro-flaw pond drainage ! topo ponds real (kind=dbl_kind), public :: & @@ -370,8 +386,14 @@ module icepack_parameters 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 for snow (kg s/m^4) - snwlvlfac = 0.3_dbl_kind ! fractional increase in snow + snwlvlfac = 0.3_dbl_kind, & ! fractional increase in snow ! depth for bulk redistribution + snw_growth_wet = 4.22e5_dbl_kind, & ! wet metamorphism parameter (um^3/s) + ! 1.e18 * 4.22e-13 (Oleson 2010) + drsnw_min = 0.0_dbl_kind, & ! minimum snow grain growth factor + snwliq_max = 0.033_dbl_kind ! irreducible saturation fraction + ! 0.033 (Anderson 1976) + ! 0.09 to 0.1 (Denoth et al, 1979 & Brun 1989) ! indices for aging lookup table integer (kind=int_kind), public :: & isnw_T, & ! maximum temperature index @@ -411,9 +433,7 @@ module icepack_parameters phi_snow = -1.0_dbl_kind , & ! snow porosity (compute from snow density if negative) grid_o = 0.006_dbl_kind , & ! for bottom flux initbio_frac = c1 , & ! fraction of ocean trcr concentration in bio trcrs - l_sk = 2.0_dbl_kind , & ! characteristic diffusive scale (m) - grid_oS = c0 , & ! for bottom flux - l_skS = 0.028_dbl_kind , & ! characteristic skeletal layer thickness (m) (zsalinity) + l_sk = 2.0_dbl_kind , & ! characteristic diffusive scale brine (m) algal_vel = 1.0e-7_dbl_kind , & ! 0.5 cm/d(m/s) Lavoie 2005 1.5 cm/day R_dFe2dust = 0.035_dbl_kind , & ! g/g (3.5% content) Tagliabue 2009 dustFe_sol = 0.005_dbl_kind , & ! solubility fraction @@ -554,16 +574,15 @@ subroutine icepack_init_parameters( & stefan_boltzmann_in, ice_ref_salinity_in, & Tffresh_in, Lsub_in, Lvap_in, Timelt_in, Tsmelt_in, & iceruf_in, Cf_in, Pstar_in, Cstar_in, kappav_in, & - kice_in, ksno_in, & + kice_in, ksno_in, itd_area_min_in, itd_mass_min_in, & zref_in, hs_min_in, snowpatch_in, rhosi_in, sk_l_in, & - saltmax_in, phi_init_in, min_salin_in, salt_loss_in, & - Tliquidus_max_in, & + saltmax_in, phi_init_in, min_salin_in, Tliquidus_max_in, & min_bgc_in, dSin0_frazil_in, hi_ssl_in, hs_ssl_in, hs_ssl_min_in, & awtvdr_in, awtidr_in, awtvdf_in, awtidf_in, & qqqice_in, TTTice_in, qqqocn_in, TTTocn_in, & - ktherm_in, conduct_in, fbot_xfer_type_in, calc_Tsfc_in, dts_b_in, & + ktherm_in, conduct_in, fbot_xfer_type_in, calc_Tsfc_in, & update_ocn_f_in, ustar_min_in, hi_min_in, a_rapid_mode_in, & - cpl_frazil_in, & + cpl_frazil_in, semi_implicit_Tsfc_in, vapor_flux_correction_in, & Rac_rapid_mode_in, aspect_rapid_mode_in, & dSdt_slow_mode_in, phi_c_slow_mode_in, & phi_i_mushy_in, shortwave_in, albedo_type_in, albsnowi_in, & @@ -573,13 +592,12 @@ subroutine icepack_init_parameters( & atmbndy_in, calc_strair_in, formdrag_in, highfreq_in, natmiter_in, & atmiter_conv_in, calc_dragio_in, & tfrz_option_in, kitd_in, kcatbound_in, hs0_in, frzpnd_in, & - saltflux_option_in, congel_freeze_in, & + apnd_sl_in, saltflux_option_in, congel_freeze_in, & floeshape_in, wave_spec_in, wave_spec_type_in, wave_height_type_in, nfreq_in, & dpscale_in, rfracmin_in, rfracmax_in, pndaspect_in, hs1_in, hp1_in, & bgc_flux_type_in, z_tracers_in, scale_bgc_in, solve_zbgc_in, & modal_aero_in, use_macromolecules_in, restartbgc_in, skl_bgc_in, & - solve_zsal_in, grid_o_in, l_sk_in, & - initbio_frac_in, grid_oS_in, l_skS_in, dEdd_algae_in, & + grid_o_in, l_sk_in, initbio_frac_in, dEdd_algae_in, & phi_snow_in, T_max_in, fsal_in, use_atm_dust_iron_in, & fr_resp_in, algal_vel_in, R_dFe2dust_in, dustFe_sol_in, & op_dep_min_in, fr_graze_s_in, fr_graze_e_in, fr_mort2min_in, & @@ -588,6 +606,7 @@ 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, snwgrain_in, & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & + snw_growth_wet_in, drsnw_min_in, snwliq_max_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, & @@ -679,7 +698,6 @@ subroutine icepack_init_parameters( & saltmax_in, & ! max salinity at ice base for BL99 (ppt) phi_init_in, & ! initial liquid fraction of frazil min_salin_in, & ! threshold for brine pocket treatment - salt_loss_in, & ! fraction of salt retained in zsalinity Tliquidus_max_in, & ! maximum liquidus temperature of mush (C) dSin0_frazil_in ! bulk salinity reduction of newly formed frazil @@ -698,10 +716,12 @@ subroutine icepack_init_parameters( & calc_Tsfc_in , &! if true, calculate surface temperature ! if false, Tsfc is computed elsewhere and ! atmos-ice fluxes are provided to CICE + semi_implicit_Tsfc_in , &! compute dfsurf/dT, dflat/dT terms instead of fsurf, flat + vapor_flux_correction_in, &! compute mass/enthalpy correction when evaporation/sublimation + ! computed outside at 0C update_ocn_f_in ! include fresh water and salt fluxes for frazil real (kind=dbl_kind), intent(in), optional :: & - dts_b_in, & ! zsalinity timestep hi_min_in, & ! minimum ice thickness allowed (m) for thermo ustar_min_in ! minimum friction velocity for ice-ocean heat flux @@ -784,14 +804,16 @@ subroutine icepack_init_parameters( & !----------------------------------------------------------------------- real(kind=dbl_kind), intent(in), optional :: & - Cf_in, & ! ratio of ridging work to PE change in ridging - Pstar_in, & ! constant in Hibler strength formula - Cstar_in, & ! constant in Hibler strength formula - dragio_in, & ! ice-ocn drag coefficient + itd_area_min_in, & ! zap residual ice below this minimum area + itd_mass_min_in, & ! zap residual ice below this minimum mass + Cf_in, & ! ratio of ridging work to PE change in ridging + Pstar_in, & ! constant in Hibler strength formula + Cstar_in, & ! constant in Hibler strength formula + dragio_in, & ! ice-ocn drag coefficient thickness_ocn_layer1_in, & ! thickness of first ocean level (m) - iceruf_ocn_in, & ! under-ice roughness (m) - gravit_in, & ! gravitational acceleration (m/s^2) - iceruf_in ! ice surface roughness (m) + iceruf_ocn_in, & ! under-ice roughness (m) + gravit_in, & ! gravitational acceleration (m/s^2) + iceruf_in ! ice surface roughness (m) integer (kind=int_kind), intent(in), optional :: & ! defined in namelist kstrength_in , & ! 0 for simple Hibler (1979) formulation @@ -887,20 +909,15 @@ subroutine icepack_init_parameters( & conserv_check_in ! if .true., run conservation checks and abort if checks fail logical (kind=log_kind), intent(in), optional :: & - skl_bgc_in, & ! if true, solve skeletal biochemistry - solve_zsal_in ! if true, update salinity profile from solve_S_dt + skl_bgc_in ! if true, solve skeletal biochemistry real (kind=dbl_kind), intent(in), optional :: & grid_o_in , & ! for bottom flux - l_sk_in , & ! characteristic diffusive scale (zsalinity) (m) + l_sk_in , & ! characteristic diffusive scale (m) grid_o_t_in , & ! top grid point length scale initbio_frac_in, & ! fraction of ocean tracer concentration used to initialize tracer phi_snow_in ! snow porosity at the ice/snow interface - real (kind=dbl_kind), intent(in), optional :: & - grid_oS_in , & ! for bottom flux (zsalinity) - l_skS_in ! 0.02 characteristic skeletal layer thickness (m) (zsalinity) - real (kind=dbl_kind), intent(in), optional :: & ratio_Si2N_diatoms_in, & ! algal Si to N (mol/mol) ratio_Si2N_sp_in , & @@ -1034,7 +1051,7 @@ subroutine icepack_init_parameters( & real (kind=dbl_kind), intent(in), optional :: & hs0_in ! snow depth for transition to bare sea ice (m) - ! level-ice ponds + ! level-ice and sealvl ponds character (len=*), intent(in), optional :: & frzpnd_in ! pond refreezing parameterization @@ -1045,6 +1062,10 @@ subroutine icepack_init_parameters( & pndaspect_in, & ! ratio of pond depth to pond fraction hs1_in ! tapering parameter for snow on pond ice + ! sealvl ponds + real (kind=dbl_kind), intent(in), optional :: & + apnd_sl_in ! equilibrium pond fraction for sea level parameterization + ! topo ponds real (kind=dbl_kind), intent(in), optional :: & hp1_in ! critical parameter for pond ice thickness @@ -1069,7 +1090,10 @@ 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 + snw_growth_wet_in,&! wet metamorphism parameter (um^3/s) + drsnw_min_in, & ! minimum snow grain growth factor + snwliq_max_in ! irreducible saturation fraction integer (kind=int_kind), intent(in), optional :: & isnw_T_in, & ! maxiumum temperature index @@ -1134,6 +1158,8 @@ subroutine icepack_init_parameters( & if (present(Tsmelt_in) ) Tsmelt = Tsmelt_in if (present(ice_ref_salinity_in) ) ice_ref_salinity = ice_ref_salinity_in if (present(iceruf_in) ) iceruf = iceruf_in + if (present(itd_area_min_in) ) itd_area_min = itd_area_min_in + if (present(itd_mass_min_in) ) itd_mass_min = itd_mass_min_in if (present(Cf_in) ) Cf = Cf_in if (present(Pstar_in) ) Pstar = Pstar_in if (present(Cstar_in) ) Cstar = Cstar_in @@ -1148,7 +1174,6 @@ subroutine icepack_init_parameters( & if (present(saltmax_in) ) saltmax = saltmax_in if (present(phi_init_in) ) phi_init = phi_init_in if (present(min_salin_in) ) min_salin = min_salin_in - if (present(salt_loss_in) ) salt_loss = salt_loss_in if (present(Tliquidus_max_in) ) Tliquidus_max = Tliquidus_max_in if (present(min_bgc_in) ) min_bgc = min_bgc_in if (present(dSin0_frazil_in) ) dSin0_frazil = dSin0_frazil_in @@ -1168,9 +1193,10 @@ subroutine icepack_init_parameters( & if (present(conduct_in) ) conduct = conduct_in if (present(fbot_xfer_type_in) ) fbot_xfer_type = fbot_xfer_type_in if (present(calc_Tsfc_in) ) calc_Tsfc = calc_Tsfc_in + if (present(semi_implicit_Tsfc_in)) semi_implicit_Tsfc= semi_implicit_Tsfc_in + if (present(vapor_flux_correction_in)) vapor_flux_correction= vapor_flux_correction_in if (present(cpl_frazil_in) ) cpl_frazil = cpl_frazil_in if (present(update_ocn_f_in) ) update_ocn_f = update_ocn_f_in - if (present(dts_b_in) ) dts_b = dts_b_in if (present(ustar_min_in) ) ustar_min = ustar_min_in if (present(hi_min_in) ) hi_min = hi_min_in if (present(a_rapid_mode_in) ) a_rapid_mode = a_rapid_mode_in @@ -1219,6 +1245,7 @@ subroutine icepack_init_parameters( & if (present(rfracmin_in) ) rfracmin = rfracmin_in if (present(rfracmax_in) ) rfracmax = rfracmax_in if (present(pndaspect_in) ) pndaspect = pndaspect_in + if (present(apnd_sl_in) ) apnd_sl = apnd_sl_in if (present(hs1_in) ) hs1 = hs1_in if (present(hp1_in) ) hp1 = hp1_in if (present(snwredist_in) ) snwredist = snwredist_in @@ -1233,6 +1260,9 @@ 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(snw_growth_wet_in) ) snw_growth_wet = snw_growth_wet_in + if (present(drsnw_min_in) ) drsnw_min = drsnw_min_in + if (present(snwliq_max_in) ) snwliq_max = snwliq_max_in !------------------- ! SNOW table @@ -1365,19 +1395,11 @@ subroutine icepack_init_parameters( & if (present(restartbgc_in) ) restartbgc = restartbgc_in if (present(conserv_check_in) ) conserv_check = conserv_check_in if (present(skl_bgc_in) ) skl_bgc = skl_bgc_in - if (present(solve_zsal_in)) then - call icepack_warnings_add(subname//' WARNING: zsalinity is deprecated') - if (solve_zsal_in) then - call icepack_warnings_setabort(.true.,__FILE__,__LINE__) - endif - endif if (present(grid_o_in) ) grid_o = grid_o_in if (present(l_sk_in) ) l_sk = l_sk_in if (present(grid_o_t_in) ) grid_o_t = grid_o_t_in if (present(frazil_scav_in) ) frazil_scav = frazil_scav_in if (present(initbio_frac_in) ) initbio_frac = initbio_frac_in - if (present(grid_oS_in) ) grid_oS = grid_oS_in - if (present(l_skS_in) ) l_skS = l_skS_in if (present(phi_snow_in) ) phi_snow = phi_snow_in if (present(ratio_Si2N_diatoms_in) ) ratio_Si2N_diatoms = ratio_Si2N_diatoms_in @@ -1567,31 +1589,29 @@ subroutine icepack_query_parameters( & stefan_boltzmann_out, ice_ref_salinity_out, & Tffresh_out, Lsub_out, Lvap_out, Timelt_out, Tsmelt_out, & iceruf_out, Cf_out, Pstar_out, Cstar_out, kappav_out, & - kice_out, ksno_out, & + kice_out, ksno_out, itd_area_min_out, itd_mass_min_out, & zref_out, hs_min_out, snowpatch_out, rhosi_out, sk_l_out, & - saltmax_out, phi_init_out, min_salin_out, salt_loss_out, & - Tliquidus_max_out, & + saltmax_out, phi_init_out, min_salin_out, Tliquidus_max_out, & min_bgc_out, dSin0_frazil_out, hi_ssl_out, hs_ssl_out, hs_ssl_min_out, & awtvdr_out, awtidr_out, awtvdf_out, awtidf_out, cpl_frazil_out, & qqqice_out, TTTice_out, qqqocn_out, TTTocn_out, update_ocn_f_out, & Lfresh_out, cprho_out, Cp_out, ustar_min_out, hi_min_out, a_rapid_mode_out, & - ktherm_out, conduct_out, fbot_xfer_type_out, calc_Tsfc_out, dts_b_out, & + ktherm_out, conduct_out, fbot_xfer_type_out, calc_Tsfc_out, & Rac_rapid_mode_out, aspect_rapid_mode_out, dSdt_slow_mode_out, & - phi_c_slow_mode_out, phi_i_mushy_out, shortwave_out, & - albedo_type_out, albicev_out, albicei_out, albsnowv_out, & + phi_c_slow_mode_out, phi_i_mushy_out, shortwave_out, semi_implicit_Tsfc_out, & + albedo_type_out, albicev_out, albicei_out, albsnowv_out, vapor_flux_correction_out, & albsnowi_out, ahmax_out, R_ice_out, R_pnd_out, R_snw_out, dT_mlt_out, & rsnw_mlt_out, dEdd_algae_out, & kalg_out, R_gC2molC_out, kstrength_out, krdg_partic_out, krdg_redist_out, mu_rdg_out, & atmbndy_out, calc_strair_out, formdrag_out, highfreq_out, natmiter_out, & atmiter_conv_out, calc_dragio_out, & tfrz_option_out, kitd_out, kcatbound_out, hs0_out, frzpnd_out, & - saltflux_option_out, congel_freeze_out, & + apnd_sl_out, saltflux_option_out, congel_freeze_out, & floeshape_out, wave_spec_out, wave_spec_type_out, wave_height_type_out, nfreq_out, & dpscale_out, rfracmin_out, rfracmax_out, pndaspect_out, hs1_out, hp1_out, & bgc_flux_type_out, z_tracers_out, scale_bgc_out, solve_zbgc_out, & modal_aero_out, use_macromolecules_out, restartbgc_out, use_atm_dust_iron_out, & - skl_bgc_out, solve_zsal_out, grid_o_out, l_sk_out, & - initbio_frac_out, grid_oS_out, l_skS_out, & + skl_bgc_out, grid_o_out, l_sk_out, initbio_frac_out, & phi_snow_out, conserv_check_out, & fr_resp_out, algal_vel_out, R_dFe2dust_out, dustFe_sol_out, & T_max_out, fsal_out, op_dep_min_out, fr_graze_s_out, fr_graze_e_out, & @@ -1600,6 +1620,7 @@ 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, snwgrain_out, & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & + snw_growth_wet_out, drsnw_min_out, snwliq_max_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, & @@ -1699,7 +1720,6 @@ subroutine icepack_query_parameters( & saltmax_out, & ! max salinity at ice base for BL99 (ppt) phi_init_out, & ! initial liquid fraction of frazil min_salin_out, & ! threshold for brine pocket treatment - salt_loss_out, & ! fraction of salt retained in zsalinity Tliquidus_max_out, & ! maximum liquidus temperature of mush (C) dSin0_frazil_out ! bulk salinity reduction of newly formed frazil @@ -1718,10 +1738,12 @@ subroutine icepack_query_parameters( & calc_Tsfc_out ,&! if true, calculate surface temperature ! if false, Tsfc is computed elsewhere and ! atmos-ice fluxes are provided to CICE + semi_implicit_Tsfc_out ,&! compute dfsurf/dT, dflat/dT terms instead of fsurf, flat + vapor_flux_correction_out ,&! compute mass/enthalpy correction when evaporation/sublimation + ! computed outside at 0C update_ocn_f_out ! include fresh water and salt fluxes for frazil real (kind=dbl_kind), intent(out), optional :: & - dts_b_out, & ! zsalinity timestep hi_min_out, & ! minimum ice thickness allowed (m) for thermo ustar_min_out ! minimum friction velocity for ice-ocean heat flux @@ -1806,14 +1828,16 @@ subroutine icepack_query_parameters( & !----------------------------------------------------------------------- real(kind=dbl_kind), intent(out), optional :: & - Cf_out, & ! ratio of ridging work to PE change in ridging - Pstar_out, & ! constant in Hibler strength formula - Cstar_out, & ! constant in Hibler strength formula - dragio_out, & ! ice-ocn drag coefficient + itd_area_min_out, & ! zap residual ice below this minimum area + itd_mass_min_out, & ! zap residual ice below this minimum mass + Cf_out, & ! ratio of ridging work to PE change in ridging + Pstar_out, & ! constant in Hibler strength formula + Cstar_out, & ! constant in Hibler strength formula + dragio_out, & ! ice-ocn drag coefficient thickness_ocn_layer1_out, & ! thickness of first ocean level (m) - iceruf_ocn_out, & ! under-ice roughness (m) - gravit_out, & ! gravitational acceleration (m/s^2) - iceruf_out ! ice surface roughness (m) + iceruf_ocn_out, & ! under-ice roughness (m) + gravit_out, & ! gravitational acceleration (m/s^2) + iceruf_out ! ice surface roughness (m) integer (kind=int_kind), intent(out), optional :: & ! defined in namelist kstrength_out , & ! 0 for simple Hibler (1979) formulation @@ -1909,20 +1933,15 @@ subroutine icepack_query_parameters( & conserv_check_out ! if .true., run conservation checks and abort if checks fail logical (kind=log_kind), intent(out), optional :: & - skl_bgc_out, & ! if true, solve skeletal biochemistry - solve_zsal_out ! if true, update salinity profile from solve_S_dt + skl_bgc_out ! if true, solve skeletal biochemistry real (kind=dbl_kind), intent(out), optional :: & grid_o_out , & ! for bottom flux - l_sk_out , & ! characteristic diffusive scale (zsalinity) (m) + l_sk_out , & ! characteristic diffusive scale (m) grid_o_t_out , & ! top grid point length scale initbio_frac_out, & ! fraction of ocean tracer concentration used to initialize tracer phi_snow_out ! snow porosity at the ice/snow interface - real (kind=dbl_kind), intent(out), optional :: & - grid_oS_out , & ! for bottom flux (zsalinity) - l_skS_out ! 0.02 characteristic skeletal layer thickness (m) (zsalinity) - real (kind=dbl_kind), intent(out), optional :: & ratio_Si2N_diatoms_out, & ! algal Si to N (mol/mol) ratio_Si2N_sp_out , & @@ -2056,7 +2075,7 @@ subroutine icepack_query_parameters( & real (kind=dbl_kind), intent(out), optional :: & hs0_out ! snow depth for transition to bare sea ice (m) - ! level-ice ponds + ! level-ice and sealvl ponds character (len=*), intent(out), optional :: & frzpnd_out ! pond refreezing parameterization @@ -2067,6 +2086,10 @@ subroutine icepack_query_parameters( & pndaspect_out, & ! ratio of pond depth to pond fraction hs1_out ! tapering parameter for snow on pond ice + ! sealvl ponds + real (kind=dbl_kind), intent(out), optional :: & + apnd_sl_out ! equilibrium pond fraction for sea level parameterization + ! topo ponds real (kind=dbl_kind), intent(out), optional :: & hp1_out ! critical parameter for pond ice thickness @@ -2091,7 +2114,10 @@ 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 + snw_growth_wet_out,&! wet metamorphism parameter (um^3/s) + drsnw_min_out, & ! minimum snow grain growth factor + snwliq_max_out ! irreducible saturation fraction integer (kind=int_kind), intent(out), optional :: & isnw_T_out, & ! maxiumum temperature index @@ -2189,6 +2215,8 @@ subroutine icepack_query_parameters( & if (present(ice_ref_salinity_out) ) ice_ref_salinity_out = ice_ref_salinity if (present(iceruf_out) ) iceruf_out = iceruf if (present(Cf_out) ) Cf_out = Cf + if (present(itd_area_min_out) ) itd_area_min_out = itd_area_min + if (present(itd_mass_min_out) ) itd_mass_min_out = itd_mass_min if (present(Pstar_out) ) Pstar_out = Pstar if (present(Cstar_out) ) Cstar_out = Cstar if (present(kappav_out) ) kappav_out = kappav @@ -2202,7 +2230,6 @@ subroutine icepack_query_parameters( & if (present(saltmax_out) ) saltmax_out = saltmax if (present(phi_init_out) ) phi_init_out = phi_init if (present(min_salin_out) ) min_salin_out = min_salin - if (present(salt_loss_out) ) salt_loss_out = salt_loss if (present(Tliquidus_max_out) ) Tliquidus_max_out= Tliquidus_max if (present(min_bgc_out) ) min_bgc_out = min_bgc if (present(dSin0_frazil_out) ) dSin0_frazil_out = dSin0_frazil @@ -2222,9 +2249,10 @@ subroutine icepack_query_parameters( & if (present(conduct_out) ) conduct_out = conduct if (present(fbot_xfer_type_out) ) fbot_xfer_type_out = fbot_xfer_type if (present(calc_Tsfc_out) ) calc_Tsfc_out = calc_Tsfc + if (present(semi_implicit_Tsfc_out)) semi_implicit_Tsfc_out= semi_implicit_Tsfc + if (present(vapor_flux_correction_out)) vapor_flux_correction_out= vapor_flux_correction if (present(cpl_frazil_out) ) cpl_frazil_out = cpl_frazil if (present(update_ocn_f_out) ) update_ocn_f_out = update_ocn_f - if (present(dts_b_out) ) dts_b_out = dts_b if (present(ustar_min_out) ) ustar_min_out = ustar_min if (present(hi_min_out) ) hi_min_out = hi_min if (present(a_rapid_mode_out) ) a_rapid_mode_out = a_rapid_mode @@ -2273,6 +2301,7 @@ subroutine icepack_query_parameters( & if (present(rfracmin_out) ) rfracmin_out = rfracmin if (present(rfracmax_out) ) rfracmax_out = rfracmax if (present(pndaspect_out) ) pndaspect_out = pndaspect + if (present(apnd_sl_out) ) apnd_sl_out = apnd_sl if (present(hs1_out) ) hs1_out = hs1 if (present(hp1_out) ) hp1_out = hp1 if (present(snwredist_out) ) snwredist_out = snwredist @@ -2287,6 +2316,9 @@ 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(snw_growth_wet_out) ) snw_growth_wet_out = snw_growth_wet + if (present(drsnw_min_out) ) drsnw_min_out = drsnw_min + if (present(snwliq_max_out) ) snwliq_max_out = snwliq_max 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 @@ -2308,13 +2340,10 @@ subroutine icepack_query_parameters( & if (present(restartbgc_out) ) restartbgc_out= restartbgc if (present(conserv_check_out) ) conserv_check_out= conserv_check if (present(skl_bgc_out) ) skl_bgc_out = skl_bgc - if (present(solve_zsal_out) ) solve_zsal_out = solve_zsal if (present(grid_o_out) ) grid_o_out = grid_o if (present(l_sk_out) ) l_sk_out = l_sk if (present(initbio_frac_out) ) initbio_frac_out = initbio_frac if (present(frazil_scav_out) ) frazil_scav_out = frazil_scav - if (present(grid_oS_out) ) grid_oS_out = grid_oS - if (present(l_skS_out) ) l_skS_out = l_skS if (present(grid_o_t_out) ) grid_o_t_out = grid_o_t if (present(phi_snow_out) ) phi_snow_out = phi_snow if (present(ratio_Si2N_diatoms_out) ) ratio_Si2N_diatoms_out = ratio_Si2N_diatoms @@ -2488,6 +2517,8 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " Tsmelt = ",Tsmelt write(iounit,*) " ice_ref_salinity = ",ice_ref_salinity write(iounit,*) " iceruf = ",iceruf + write(iounit,*) " itd_area_min = ",itd_area_min + write(iounit,*) " itd_mass_min = ",itd_mass_min write(iounit,*) " Cf = ",Cf write(iounit,*) " Pstar = ",Pstar write(iounit,*) " Cstar = ",Cstar @@ -2502,7 +2533,6 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " saltmax = ",saltmax write(iounit,*) " phi_init = ",phi_init write(iounit,*) " min_salin = ",min_salin - write(iounit,*) " salt_loss = ",salt_loss write(iounit,*) " Tliquidus_max = ",Tliquidus_max write(iounit,*) " min_bgc = ",min_bgc write(iounit,*) " dSin0_frazil = ",dSin0_frazil @@ -2533,9 +2563,10 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " conduct = ", trim(conduct) write(iounit,*) " fbot_xfer_type = ", trim(fbot_xfer_type) write(iounit,*) " calc_Tsfc = ", calc_Tsfc + write(iounit,*) " semi_implicit_Tsfc = ", semi_implicit_Tsfc + write(iounit,*) " vapor_flux_correction = ", vapor_flux_correction write(iounit,*) " cpl_frazil = ", cpl_frazil write(iounit,*) " update_ocn_f = ", update_ocn_f - write(iounit,*) " dts_b = ", dts_b write(iounit,*) " ustar_min = ", ustar_min write(iounit,*) " hi_min = ", hi_min write(iounit,*) " a_rapid_mode = ", a_rapid_mode @@ -2584,6 +2615,7 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " rfracmin = ", rfracmin write(iounit,*) " rfracmax = ", rfracmax write(iounit,*) " pndaspect = ", pndaspect + write(iounit,*) " apnd_sl = ", apnd_sl write(iounit,*) " hs1 = ", hs1 write(iounit,*) " hp1 = ", hp1 write(iounit,*) " snwredist = ", trim(snwredist) @@ -2598,6 +2630,9 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " windmin = ", windmin write(iounit,*) " drhosdwind = ", drhosdwind write(iounit,*) " snwlvlfac = ", snwlvlfac + write(iounit,*) " snw_growth_wet = ", snw_growth_wet + write(iounit,*) " drsnw_min = ", drsnw_min + write(iounit,*) " snwliq_max = ", snwliq_max write(iounit,*) " isnw_T = ", isnw_T write(iounit,*) " isnw_Tgrd = ", isnw_Tgrd write(iounit,*) " isnw_rhos = ", isnw_rhos @@ -2619,14 +2654,11 @@ subroutine icepack_write_parameters(iounit) write(iounit,*) " restartbgc = ", restartbgc write(iounit,*) " conserv_check = ", conserv_check write(iounit,*) " skl_bgc = ", skl_bgc - write(iounit,*) " solve_zsal = ", solve_zsal write(iounit,*) " grid_o = ", grid_o write(iounit,*) " l_sk = ", l_sk write(iounit,*) " grid_o_t = ", grid_o_t write(iounit,*) " initbio_frac = ", initbio_frac write(iounit,*) " frazil_scav= ", frazil_scav - write(iounit,*) " grid_oS = ", grid_oS - write(iounit,*) " l_skS = ", l_skS write(iounit,*) " phi_snow = ", phi_snow write(iounit,*) " ratio_Si2N_diatoms = ", ratio_Si2N_diatoms diff --git a/columnphysics/icepack_shortwave.F90 b/columnphysics/icepack_shortwave.F90 index 7a3e5a4e..af3f0f65 100644 --- a/columnphysics/icepack_shortwave.F90 +++ b/columnphysics/icepack_shortwave.F90 @@ -51,12 +51,14 @@ module icepack_shortwave use icepack_parameters, only: z_tracers, skl_bgc, calc_tsfc, shortwave, kalg 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_parameters, only: snw_ssp_table, modal_aero + use icepack_parameters, only: snw_ssp_table, modal_aero, semi_implicit_Tsfc use icepack_parameters, only: dEdd_algae + use icepack_parameters, only: hpmin, hp0 use icepack_tracers, only: ncat, nilyr, nslyr, nblyr use icepack_tracers, only: ntrcr, nbtrcr_sw - use icepack_tracers, only: tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_lvl, tr_pond_topo, tr_pond_sealvl + use icepack_tracers, only: tr_lvl use icepack_tracers, only: tr_bgc_N, tr_aero use icepack_tracers, only: nt_bgc_N, nt_zaero use icepack_tracers, only: tr_zaero, nlt_chl_sw, nlt_zaero_sw @@ -114,10 +116,6 @@ module icepack_shortwave icepack_init_radiation, & icepack_step_radiation - real (kind=dbl_kind), parameter :: & - hpmin = 0.005_dbl_kind, & ! minimum allowed melt pond depth (m) - hp0 = 0.200_dbl_kind ! pond depth below which transition to bare ice - real (kind=dbl_kind), parameter :: & exp_argmax = c10 ! maximum argument of exponential @@ -223,11 +221,17 @@ subroutine shortwave_ccsm3 (aicen, vicen, & alvdrn, alidrn, & alvdfn, alidfn, & fswsfc, fswint, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & fswthrun, & fswthrun_vdr, & fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswpenl, & Iswabs, SSwabs, & albin, albsn, & @@ -245,6 +249,12 @@ subroutine shortwave_ccsm3 (aicen, vicen, & swidr , & ! sw down, near IR, direct (W/m^2) swidf ! sw down, near IR, diffuse (W/m^2) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr , & ! sw down, ultraviolet, direct (W/m^2) + swuvrdf , & ! sw down, ultraviolet, diffuse (W/m^2) + swpardr , & ! sw down, PAR, direct (W/m^2) + swpardf ! sw down, PAR, diffuse (W/m^2) + ! baseline albedos for ccsm3 shortwave, set in namelist real (kind=dbl_kind), intent(in) :: & albicev , & ! visible ice albedo for h > ahmax @@ -271,7 +281,11 @@ subroutine shortwave_ccsm3 (aicen, vicen, & fswthrun_vdr, & ! vis dir SW through ice to ocean (W m-2) fswthrun_vdf, & ! vis dif SW through ice to ocean (W m-2) fswthrun_idr, & ! nir dir SW through ice to ocean (W m-2) - fswthrun_idf ! nir dif SW through ice to ocean (W m-2) + fswthrun_idf, & ! nir dif SW through ice to ocean (W m-2) + fswthrun_uvrdr,&! uv dir SW through ice to ocean (W m-2) + fswthrun_uvrdf,&! uv dif SW through ice to ocean (W m-2) + fswthrun_pardr,&! par dir SW through ice to ocean (W m-2) + fswthrun_pardf ! par dif SW through ice to ocean (W m-2) real (kind=dbl_kind), intent(inout) :: & coszen ! cosine(zenith angle) @@ -303,8 +317,11 @@ subroutine shortwave_ccsm3 (aicen, vicen, & l_fswthru_vdr, & ! vis dir SW through ice to ocean (W m-2) l_fswthru_vdf, & ! vis dif SW through ice to ocean (W m-2) l_fswthru_idr, & ! nir dir SW through ice to ocean (W m-2) - l_fswthru_idf ! nir dif SW through ice to ocean (W m-2) - + l_fswthru_idf, & ! nir dif SW through ice to ocean (W m-2) + l_fswthru_uvrdr,&! uv dir SW through ice to ocean (W m-2) + l_fswthru_uvrdf,&! uv dif SW through ice to ocean (W m-2) + l_fswthru_pardr,&! par dir SW through ice to ocean (W m-2) + l_fswthru_pardf ! par dif SW through ice to ocean (W m-2) character(len=*),parameter :: subname='(shortwave_ccsm3)' !----------------------------------------------------------------- @@ -407,6 +424,10 @@ subroutine shortwave_ccsm3 (aicen, vicen, & alidrni, alidfni, & alvdrns, alvdfns, & alidrns, alidfns, & + swuvrdr=swuvrdr, & + swuvrdf=swuvrdf, & + swpardr=swpardr, & + swpardf=swpardf, & fswsfc=fswsfc(n), & fswint=fswint(n), & fswthru=fswthrun(n), & @@ -414,6 +435,10 @@ subroutine shortwave_ccsm3 (aicen, vicen, & fswthru_vdf=l_fswthru_vdf, & fswthru_idr=l_fswthru_idr, & fswthru_idf=l_fswthru_idf, & + fswthru_uvrdr=l_fswthru_uvrdr,& + fswthru_uvrdf=l_fswthru_uvrdf,& + fswthru_pardr=l_fswthru_pardr,& + fswthru_pardf=l_fswthru_pardf,& fswpenl=fswpenl(:,n), & Iswabs=Iswabs(:,n)) @@ -423,6 +448,10 @@ subroutine shortwave_ccsm3 (aicen, vicen, & if (present(fswthrun_vdf)) fswthrun_vdf(n) = l_fswthru_vdf if (present(fswthrun_idr)) fswthrun_idr(n) = l_fswthru_idr if (present(fswthrun_idf)) fswthrun_idf(n) = l_fswthru_idf + if (present(fswthrun_uvrdr)) fswthrun_uvrdr(n) = l_fswthru_uvrdr + if (present(fswthrun_uvrdf)) fswthrun_uvrdf(n) = l_fswthru_uvrdf + if (present(fswthrun_pardr)) fswthrun_pardr(n) = l_fswthru_pardr + if (present(fswthrun_pardf)) fswthrun_pardf(n) = l_fswthru_pardf endif ! aicen > puny @@ -677,12 +706,18 @@ subroutine absorbed_solar (aicen, & alidrni, alidfni, & alvdrns, alvdfns, & alidrns, alidfns, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & fswsfc, fswint, & fswthru, & fswthru_vdr, & fswthru_vdf, & fswthru_idr, & fswthru_idf, & + fswthru_uvrdr, & + fswthru_uvrdf, & + fswthru_pardr, & + fswthru_pardf, & fswpenl, & Iswabs) @@ -703,6 +738,12 @@ subroutine absorbed_solar (aicen, & alvdfns , & ! visible, diffuse albedo, snow alidfns ! near-ir, diffuse albedo, snow + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr , & ! sw down, uv dir (W/m^2) + swuvrdf , & ! sw down, uv dif (W/m^2) + swpardr , & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + real (kind=dbl_kind), intent(out):: & fswsfc , & ! SW absorbed at ice/snow surface (W m-2) fswint , & ! SW absorbed in ice interior, below surface (W m-2) @@ -712,7 +753,11 @@ subroutine absorbed_solar (aicen, & fswthru_vdr , & ! vis dir SW through ice to ocean (W m-2) fswthru_vdf , & ! vis dif SW through ice to ocean (W m-2) fswthru_idr , & ! nir dir SW through ice to ocean (W m-2) - fswthru_idf ! nir dif SW through ice to ocean (W m-2) + fswthru_idf , & ! nir dif SW through ice to ocean (W m-2) + fswthru_uvrdr, & ! uv dir SW through ice to ocean (W m-2) + fswthru_uvrdf, & ! uv dif SW through ice to ocean (W m-2) + fswthru_pardr, & ! par dir SW through ice to ocean (W m-2) + fswthru_pardf ! par dif SW through ice to ocean (W m-2) real (kind=dbl_kind), dimension (:), intent(out) :: & Iswabs , & ! SW absorbed in particular layer (W m-2) @@ -742,6 +787,12 @@ subroutine absorbed_solar (aicen, & hilyr , & ! ice layer thickness asnow ! fractional area of snow cover + real (kind=dbl_kind) :: & + swuvrdrpen , & ! penetrating SW, uv dir (W/m^2) + swuvrdfpen , & ! penetrating SW, uv dif (W/m^2) + swpardrpen , & ! penetrating SW, par dir (W/m^2) + swpardfpen ! penetrating SW, par dif (W/m^2) + character(len=*),parameter :: subname='(absorbed_solar)' !----------------------------------------------------------------- @@ -750,6 +801,10 @@ subroutine absorbed_solar (aicen, & trantop = c0 tranbot = c0 + swuvrdrpen = c0 + swuvrdfpen = c0 + swpardrpen = c0 + swpardfpen = c0 hs = vsnon / aicen @@ -789,6 +844,11 @@ subroutine absorbed_solar (aicen, & ! fswpenidr = swidr * (c1-alidrni) * (c1-asnow) * i0nir ! fswpenidf = swidf * (c1-alidfni) * (c1-asnow) * i0nir + if (present(swuvrdr)) swuvrdrpen = swuvrdr * (c1-alvdrni) * (c1-asnow) * i0vis + if (present(swuvrdf)) swuvrdfpen = swuvrdf * (c1-alvdfni) * (c1-asnow) * i0vis + if (present(swpardr)) swpardrpen = swpardr * (c1-alvdrni) * (c1-asnow) * i0vis + if (present(swpardf)) swpardfpen = swpardf * (c1-alvdfni) * (c1-asnow) * i0vis + fswpen = fswpenvdr + fswpenvdf fswsfc = swabs - fswpen @@ -825,6 +885,10 @@ subroutine absorbed_solar (aicen, & fswthru_vdf = fswpenvdf * tranbot fswthru_idr = c0 fswthru_idf = c0 + fswthru_uvrdr = swuvrdrpen * tranbot + fswthru_uvrdf = swuvrdfpen * tranbot + fswthru_pardr = swpardrpen * tranbot + fswthru_pardf = swpardfpen * tranbot ! SW absorbed in ice interior fswint = fswpen - fswthru @@ -841,6 +905,7 @@ end subroutine absorbed_solar ! author: Bruce P. Briegleb, NCAR ! 2011 ECH modified for melt pond tracers ! 2013 ECH merged with NCAR version +! 2024 DCS refactored for sealvl ponds subroutine run_dEdd(dt, & aicen, vicen, & @@ -860,11 +925,17 @@ subroutine run_dEdd(dt, & alvdrn, alvdfn, & alidrn, alidfn, & fswsfcn, fswintn, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & fswthrun, & fswthrun_vdr, & fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswpenln, & Sswabsn, Iswabsn, & albicen, albsnon, & @@ -882,7 +953,7 @@ subroutine run_dEdd(dt, & yday ! day of the year character (len=char_len), intent(in), optional :: & - calendar_type ! differentiates Gregorian from other calendars + calendar_type ! differentiates proleptic_gregorian from other calendars integer (kind=int_kind), intent(in), optional :: & days_per_year ! number of days in one year @@ -900,6 +971,12 @@ subroutine run_dEdd(dt, & swidf, & ! sw down, near IR, diffuse (W/m^2) fsnow ! snowfall rate (kg/m^2 s) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr, & ! sw down, uv dir (W/m^2) + swuvrdf, & ! sw down, uv dif (W/m^2) + swpardr, & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + real(kind=dbl_kind), dimension(:), intent(in) :: & aicen, & ! concentration of ice vicen, & ! volume per unit area of ice (m) @@ -908,14 +985,14 @@ subroutine run_dEdd(dt, & alvln, & ! level-ice area fraction apndn, & ! pond area fraction hpndn, & ! pond depth (m) - ipndn ! pond refrozen lid thickness (m) + ipndn, & ! pond refrozen lid thickness (m) + ffracn ! fraction of fsurfn used to melt ipond real(kind=dbl_kind), dimension(:,:), intent(in) :: & aeron, & ! aerosols (kg/m^3) trcrn_bgcsw ! zaerosols (kg/m^3) + chlorophyll on shorthwave grid real(kind=dbl_kind), dimension(:), intent(inout) :: & - ffracn, & ! fraction of fsurfn used to melt ipond dhsn ! depth difference for snow on sea ice and pond ice real(kind=dbl_kind), intent(inout) :: & @@ -939,7 +1016,11 @@ subroutine run_dEdd(dt, & fswthrun_vdr, & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf, & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr, & ! nir dir SW through ice to ocean (W/m^2) - fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + fswthrun_idf, & ! nir dif SW through ice to ocean (W/m^2) + fswthrun_uvrdr,&! uv dir SW through ice to ocean (W/m^2) + fswthrun_uvrdf,&! uv dif SW through ice to ocean (W/m^2) + fswthrun_pardr,&! par dir SW through ice to ocean (W/m^2) + fswthrun_pardf ! par dif SW through ice to ocean (W/m^2) real(kind=dbl_kind), dimension(:,:), intent(inout) :: & Sswabsn , & ! SW radiation absorbed in snow layers (W m-2) @@ -959,10 +1040,7 @@ subroutine run_dEdd(dt, & ! snow variables for Delta-Eddington shortwave real (kind=dbl_kind) :: & fsn , & ! snow horizontal fraction - hsn , & ! snow depth (m) - hsnlvl , & ! snow depth over level ice (m) - vsn , & ! snow volume - alvl ! area fraction of level ice + hsn ! snow depth (m) real (kind=dbl_kind), dimension (nslyr) :: & rhosnwn , & ! snow density (kg/m3) @@ -970,6 +1048,7 @@ subroutine run_dEdd(dt, & ! pond variables for Delta-Eddington shortwave real (kind=dbl_kind) :: & + apondn , & ! pond fraction of category (incl. deformed) fpn , & ! pond fraction of ice cover hpn ! actual pond depth (m) @@ -977,23 +1056,16 @@ subroutine run_dEdd(dt, & n , & ! thickness category index k ! snow layer index - real (kind=dbl_kind) :: & - ipn , & ! refrozen pond ice thickness (m), mean over ice fraction - hp , & ! pond depth - hs , & ! snow depth - asnow , & ! fractional area of snow cover - rp , & ! volume fraction of retained melt water to total liquid content - 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) - tmp ! 0 or 1 - ! needed for optional fswthrun arrays when passed as scalars real (kind=dbl_kind) :: & l_fswthru_vdr , & ! vis dir SW through ice to ocean (W m-2) l_fswthru_vdf , & ! vis dif SW through ice to ocean (W m-2) l_fswthru_idr , & ! nir dir SW through ice to ocean (W m-2) - l_fswthru_idf ! nir dif SW through ice to ocean (W m-2) + l_fswthru_idf , & ! nir dif SW through ice to ocean (W m-2) + l_fswthru_uvrdr, & ! uv dir SW through ice to ocean (W m-2) + l_fswthru_uvrdf, & ! uv dif SW through ice to ocean (W m-2) + l_fswthru_pardr, & ! par dir SW through ice to ocean (W m-2) + l_fswthru_pardf ! par dif SW through ice to ocean (W m-2) logical (kind=log_kind) :: & l_initonly ! local initonly value @@ -1015,7 +1087,9 @@ subroutine run_dEdd(dt, & call compute_coszen (TLAT, TLON, yday, sec, coszen, & days_per_year, nextsw_cday, calendar_type) #else - call compute_coszen (TLAT, TLON, yday, sec, coszen) + if (.not.semi_implicit_Tsfc) then ! GEOS sets solar angles in driver level + call compute_coszen (TLAT, TLON, yday, sec, coszen) + endif #endif if (icepack_warnings_aborted(subname)) return @@ -1048,85 +1122,31 @@ subroutine run_dEdd(dt, & ! set pond properties if (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(R_snw, & - dT_mlt, rsnw_mlt, & - alvl, vsn, & - Tsfcn(n), fsn, & - hs0, hsnlvl, & - rhosnwn(:), rsnwn(:), & - l_rsnows(:)) - if (icepack_warnings_aborted(subname)) return - endif ! snwredist - - fpn = c0 ! fraction of ice covered in pond - hpn = c0 ! pond depth over fpn - ! refrozen pond lid thickness avg over ice - ! allow snow to cover pond ice - ipn = alvln(n) * apndn(n) * ipndn(n) - dhs = dhsn(n) ! snow depth difference, sea ice - pond - if (.not. l_initonly .and. ipn > puny .and. & - dhs < puny .and. fsnow*dt > hs_min) & - dhs = hsnlvl - fsnow*dt ! initialize dhs>0 - spn = hsnlvl - dhs ! snow depth on pond ice - if (.not. l_initonly .and. ipn*spn < puny) dhs = c0 - dhsn(n) = dhs ! save: constant until reset to 0 - - ! not using ipn assumes that lid ice is perfectly clear - ! if (ipn <= 0.3_dbl_kind) then - - ! fraction of ice area - fpn = apndn(n) * alvln(n) - ! pond depth over fraction fpn - hpn = hpndn(n) - - ! reduce effective pond area absorbing surface heat flux - ! due to flux already having been used to melt pond ice - fpn = (c1 - ffracn(n)) * fpn - - ! taper pond area with snow on pond ice - if (dhs > puny .and. spn >= puny .and. hs1 > puny) then - asnow = min(spn/hs1, c1) - fpn = (c1 - asnow) * fpn - endif - - ! infiltrate snow - hp = hpn - if (hp > puny) then - hs = hsnlvl - rp = rhofresh*hp/(rhofresh*hp + rhos*hs) - if (rp < p15) then - fpn = c0 - hpn = c0 - else - hmx = hs*(rhofresh - rhos)/rhofresh - tmp = max(c0, sign(c1, hp-hmx)) ! 1 if hp>=hmx, else 0 - hp = (rhofresh*hp + rhos*hs*tmp) & - / (rhofresh - rhos*(c1-tmp)) - hsn = hsn - hp*fpn*(c1-tmp) - hpn = hp * tmp - fpn = fpn * tmp - endif - endif ! hp > puny - - ! Zero out fraction of thin ponds for radiation only - if (hpn < hpmin) fpn = c0 - fsn = min(fsn, c1-fpn) - - ! endif ! masking by lid ice - apeffn(n) = fpn ! for history - + apondn = alvln(n)*apndn(n) + call shortwave_dEdd_set_eff(aicen(n), vsnon(n), & + alvln(n), apondn, & + hpndn(n), ipndn(n), & + ffracn(n), fsnow, & + dt, Tsfcn(n), & + fsn, hsn, & + dhsn(n), fpn, & + hpn, apeffn(n), & + l_rsnows(:), rhosnwn(:), & + rsnwn(:), l_initonly) + if (icepack_warnings_aborted(subname)) return + elseif (tr_pond_sealvl) then + apondn = apndn(n) + call shortwave_dEdd_set_eff(aicen(n), vsnon(n), & + alvln(n), apondn, & + hpndn(n), ipndn(n), & + ffracn(n), fsnow, & + dt, Tsfcn(n), & + fsn, hsn, & + dhsn(n), fpn, & + hpn, apeffn(n), & + l_rsnows(:), rhosnwn(:), & + rsnwn(:), l_initonly) + if (icepack_warnings_aborted(subname)) return elseif (tr_pond_topo) then ! Lid effective if thicker than hp1 if (apndn(n)*aicen(n) > puny .and. ipndn(n) < hp1) then @@ -1176,11 +1196,19 @@ subroutine run_dEdd(dt, & alvdrn(n), alvdfn(n), & alidrn(n), alidfn(n), & fswsfcn(n), fswintn(n), & + swuvrdr=swuvrdr, & + swuvrdf=swuvrdf, & + swpardr=swpardr, & + swpardf=swpardf, & fswthru=fswthrun(n), & fswthru_vdr=l_fswthru_vdr, & fswthru_vdf=l_fswthru_vdf, & fswthru_idr=l_fswthru_idr, & fswthru_idf=l_fswthru_idf, & + fswthru_uvrdr=l_fswthru_uvrdr, & + fswthru_uvrdf=l_fswthru_uvrdf, & + fswthru_pardr=l_fswthru_pardr, & + fswthru_pardf=l_fswthru_pardf, & Sswabs=Sswabsn(:,n), & Iswabs=Iswabsn(:,n), & albice=albicen(n), & @@ -1196,6 +1224,10 @@ subroutine run_dEdd(dt, & if(present(fswthrun_vdf)) fswthrun_vdf(n) = l_fswthru_vdf if(present(fswthrun_idr)) fswthrun_idr(n) = l_fswthru_idr if(present(fswthrun_idf)) fswthrun_idf(n) = l_fswthru_idf + if(present(fswthrun_uvrdr)) fswthrun_uvrdr(n) = l_fswthru_uvrdr + if(present(fswthrun_uvrdf)) fswthrun_uvrdf(n) = l_fswthru_uvrdf + if(present(fswthrun_pardr)) fswthrun_pardr(n) = l_fswthru_pardr + if(present(fswthrun_pardf)) fswthrun_pardf(n) = l_fswthru_pardf if (present(rsnow) .and. .not. snwgrain) then do k = 1,nslyr @@ -1248,11 +1280,17 @@ subroutine shortwave_dEdd (coszen, & alvdr, alvdf, & alidr, alidf, & fswsfc, fswint, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & fswthru, & fswthru_vdr, & fswthru_vdf, & fswthru_idr, & fswthru_idf, & + fswthru_uvrdr, & + fswthru_uvrdf, & + fswthru_pardr, & + fswthru_pardf, & Sswabs, & Iswabs, albice, & albsno, albpnd, & @@ -1279,6 +1317,12 @@ subroutine shortwave_dEdd (coszen, & swidr , & ! sw down, near IR, direct (W/m^2) swidf ! sw down, near IR, diffuse (W/m^2) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr , & ! sw down, uv dir (W/m^2) + swuvrdf , & ! sw down, uv dif (W/m^2) + swpardr , & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + real (kind=dbl_kind), intent(inout) :: & coszen , & ! cosine of solar zenith angle alvdr , & ! visible, direct, albedo (fraction) @@ -1293,7 +1337,11 @@ subroutine shortwave_dEdd (coszen, & fswthru_vdr , & ! vis dir SW through snow/bare ice/ponded ice into ocean (W m-2) fswthru_vdf , & ! vis dif SW through snow/bare ice/ponded ice into ocean (W m-2) fswthru_idr , & ! nir dir SW through snow/bare ice/ponded ice into ocean (W m-2) - fswthru_idf ! nir dif SW through snow/bare ice/ponded ice into ocean (W m-2) + fswthru_idf , & ! nir dif SW through snow/bare ice/ponded ice into ocean (W m-2) + fswthru_uvrdr,& ! uv dir SW through ice into ocean (W m-2) + fswthru_uvrdf,& ! uv dif SW through ice into ocean (W m-2) + fswthru_pardr,& ! par dir SW through ice into ocean (W m-2) + fswthru_pardf ! par dif SW through ice into ocean (W m-2) real (kind=dbl_kind), dimension (:), intent(inout) :: & fswpenl , & ! visible SW entering ice layers (W m-2) @@ -1372,6 +1420,10 @@ subroutine shortwave_dEdd (coszen, & fswthru_vdf = c0 fswthru_idr = c0 fswthru_idf = c0 + fswthru_uvrdr = c0 + fswthru_uvrdf = c0 + fswthru_pardr = c0 + fswthru_pardf = c0 ! compute fraction of nir down direct to total over all points: fnidr = c0 if( swidr + swidf > puny ) then @@ -1430,7 +1482,10 @@ subroutine shortwave_dEdd (coszen, & aidrl, aidfl, fswsfc, fswint, fswthru, & fswthru_vdr, fswthru_vdf, & fswthru_idr, fswthru_idf, & - Sswabs, Iswabs, fswpenl ) + fswthru_uvrdr, fswthru_uvrdf, & + fswthru_pardr, fswthru_pardf, & + Sswabs, Iswabs, fswpenl, & + swuvrdr,swuvrdf, swpardr,swpardf) if (icepack_warnings_aborted(subname)) return alvdr = alvdr + avdrl*fi @@ -1474,7 +1529,10 @@ subroutine shortwave_dEdd (coszen, & aidrl, aidfl, fswsfc, fswint, fswthru, & fswthru_vdr, fswthru_vdf, & fswthru_idr, fswthru_idf, & - Sswabs, Iswabs, fswpenl ) + fswthru_uvrdr, fswthru_uvrdf, & + fswthru_pardr, fswthru_pardf, & + Sswabs, Iswabs, fswpenl, & + swuvrdr,swuvrdf, swpardr,swpardf) endif if (icepack_warnings_aborted(subname)) return @@ -1511,7 +1569,10 @@ subroutine shortwave_dEdd (coszen, & aidrl, aidfl, fswsfc, fswint, fswthru, & fswthru_vdr, fswthru_vdf, & fswthru_idr, fswthru_idf, & - Sswabs, Iswabs, fswpenl ) + fswthru_uvrdr, fswthru_uvrdf, & + fswthru_pardr, fswthru_pardf, & + Sswabs, Iswabs, fswpenl, & + swuvrdr,swuvrdf, swpardr,swpardf) if (icepack_warnings_aborted(subname)) return alvdr = alvdr + avdrl*fp @@ -1621,7 +1682,10 @@ subroutine compute_dEdd_3bd( & alidr, alidf, fswsfc, fswint, fswthru, & fswthru_vdr, fswthru_vdf, & fswthru_idr, fswthru_idf, & - Sswabs, Iswabs, fswpenl ) + fswthru_uvrdr, fswthru_uvrdf, & + fswthru_pardr, fswthru_pardf, & + Sswabs, Iswabs, fswpenl, & + swuvrdr,swuvrdf, swpardr,swpardf) integer (kind=int_kind), intent(in) :: & klev , & ! number of radiation layers - 1 @@ -1666,13 +1730,23 @@ subroutine compute_dEdd_3bd( & fswthru_vdr, & ! vis dir SW through snow/bare ice/ponded ice into ocean (W m-2) fswthru_vdf, & ! vis dif SW through snow/bare ice/ponded ice into ocean (W m-2) fswthru_idr, & ! nir dir SW through snow/bare ice/ponded ice into ocean (W m-2) - fswthru_idf ! nir dif SW through snow/bare ice/ponded ice into ocean (W m-2) + fswthru_idf, & ! nir dif SW through snow/bare ice/ponded ice into ocean (W m-2) + fswthru_uvrdr,&! uv dir SW through ice into ocean (W m-2) + fswthru_uvrdf,&! uv dif SW through ice into ocean (W m-2) + fswthru_pardr,&! par dir SW through ice into ocean (W m-2) + fswthru_pardf ! par dif SW through ice into ocean (W m-2) real (kind=dbl_kind), dimension (:), intent(inout) :: & fswpenl, & ! visible SW entering ice layers (W m-2) Sswabs , & ! SW absorbed in snow layer (W m-2) Iswabs ! SW absorbed in ice layer (W m-2) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr, & ! sw down, uv dir (W/m^2) + swuvrdf, & ! sw down, uv dif (W/m^2) + swpardr, & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + !----------------------------------------------------------------------- ! ! Set up optical property profiles, based on snow, sea ice and ponded @@ -1801,7 +1875,11 @@ subroutine compute_dEdd_3bd( & fthruvdr, & ! vis dir shortwave through snow/bare ice/ponded ice to ocean (W/m^2) fthruvdf, & ! vis dif shortwave through snow/bare ice/ponded ice to ocean (W/m^2) fthruidr, & ! nir dir shortwave through snow/bare ice/ponded ice to ocean (W/m^2) - fthruidf ! nir dif shortwave through snow/bare ice/ponded ice to ocean (W/m^2) + fthruidf, & ! nir dif shortwave through snow/bare ice/ponded ice to ocean (W/m^2) + fthruuvrdr,&! uv dir shortwave through snow/bare ice/ponded ice to ocean (W/m^2) + fthruuvrdf,&! uv dif shortwave through snow/bare ice/ponded ice to ocean (W/m^2) + fthrupardr,&! par dir shortwave through snow/bare ice/ponded ice to ocean (W/m^2) + fthrupardf ! par dif shortwave through snow/bare ice/ponded ice to ocean (W/m^2) real (kind=dbl_kind), dimension(nslyr) :: & Sabs ! shortwave absorbed in snow layer (W m-2) @@ -1983,6 +2061,10 @@ subroutine compute_dEdd_3bd( & fthruvdf = c0 fthruidr = c0 fthruidf = c0 + fthruuvrdr = c0 + fthruuvrdf = c0 + fthrupardr = c0 + fthrupardf = c0 ! spectral weights 2 (0.7-1.19 micro-meters) and 3 (1.19-5.0 micro-meters) ! are chosen based on 1D calculations using ratio of direct to total @@ -2599,7 +2681,9 @@ subroutine compute_dEdd_3bd( & enddo ! k endif ! adjust pond iops if pond depth within specified range - if( hpmin <= hp .and. hp <= hp0 ) then + ! turn off for sea level ponds + if(.not. tr_pond_sealvl .and. & + hpmin <= hp .and. hp < hp0 ) then k = kii sig_i = ki_ssl (ns) * wi_ssl (ns) sig_p = ki_p_ssl(ns) * wi_p_ssl(ns) @@ -2712,6 +2796,10 @@ subroutine compute_dEdd_3bd( & fthru = fthru + tmp_kl fthruvdr = fthruvdr + dfdir(klevp)*swdr fthruvdf = fthruvdf + dfdif(klevp)*swdf + if (present(swuvrdr)) fthruuvrdr = dfdir(klevp)*swuvrdr + if (present(swuvrdf)) fthruuvrdf = dfdif(klevp)*swuvrdf + if (present(swpardr)) fthrupardr = dfdir(klevp)*swpardr + if (present(swpardf)) fthrupardf = dfdif(klevp)*swpardf ! if snow covered ice, set snow internal absorption; else, Sabs=0 if (srftyp == 1) then @@ -2829,6 +2917,10 @@ subroutine compute_dEdd_3bd( & fswthru_vdf = fswthru_vdf + fthruvdf*fi fswthru_idr = fswthru_idr + fthruidr*fi fswthru_idf = fswthru_idf + fthruidf*fi + fswthru_uvrdr = fswthru_uvrdr + fthruuvrdr*fi + fswthru_uvrdf = fswthru_uvrdf + fthruuvrdf*fi + fswthru_pardr = fswthru_pardr + fthrupardr*fi + fswthru_pardf = fswthru_pardf + fthrupardf*fi do k = 1, nslyr Sswabs(k) = Sswabs(k) + Sabs(k)*fi @@ -3392,6 +3484,157 @@ subroutine shortwave_dEdd_set_snow(R_snw, & endif ! snwgrain end subroutine shortwave_dEdd_set_snow +!======================================================================= +! +! Set the 'effective' snow and pond fractions and depths for dEdd +! +! author: Bruce P. Briegleb, NCAR +! 2013: E Hunke merged with NCAR version +! 2024: DCS refactored for sealvl ponds + + subroutine shortwave_dEdd_set_eff(aicen, vsnon, alvln, & + apondn, hpndn, ipndn, & + ffracn, fsnow, dt, & + Tsfcn, fsn, hsn, & + dhsn, fpn, hpn, & + apeffn, l_rsnows,rhosnwn, & + rsnwn, l_initonly) + + real (kind=dbl_kind), intent(in) :: & + aicen , & ! concentration of ice + vsnon , & ! volume per unit area of snow (m) + alvln , & ! level-ice area fraction + apondn , & ! pond area fraction of category (incl. deformed) + hpndn , & ! pond depth (m) + ipndn , & ! pond refrozen lid thickness (m) + ffracn , & ! fraction of fsurfn used to melt ipond + fsnow , & ! snowfall rate (kg/m^2 s) + dt , & ! time step (s) + Tsfcn ! surface temperature (deg C) + + real (kind=dbl_kind), intent(inout) :: & + fsn , & ! snow horizontal fraction + hsn , & ! snow depth (m) + dhsn , & ! depth difference for snow on sea ice and pond ice + fpn , & ! pond fraction of ice cover + hpn ! actual pond depth (m) + + real (kind=dbl_kind), intent(out) :: & + apeffn ! effective pond area used for radiation + + real(kind=dbl_kind), dimension(nslyr), intent(in) :: & + l_rsnows ! snow grain radius tracer (10^-6 m) + + real (kind=dbl_kind), dimension (nslyr), intent(out) :: & + rhosnwn, & ! snow density (kg/m3) + rsnwn ! snow grain radius (micrometers) + + logical (kind=log_kind), intent(in) :: & + l_initonly ! local initonly value + + ! local variables + real (kind=dbl_kind) :: & + hsnlvl , & ! snow depth over level ice (m) + vsn , & ! snow volume + alvl , & ! area fraction of level ice + ipn , & ! pond lid thickness (m), mean over category + hp , & ! pond depth + hs , & ! snow depth + asnow , & ! fractional area of snow cover + rp , & ! ratio retained melt water to total liquid content + hmx , & ! maximum available snow infiltration equiv. depth + dhs , & ! local diff. in snow depth on sea ice and pond ice + spn , & ! snow depth on refrozen pond (m) + tmp ! 0 or 1 + + character(len=*),parameter :: subname='(shortwave_dEdd_set_eff)' + +!----------------------------------------------------------------------- + hsnlvl = hsn ! initialize + if (trim(snwredist) == 'bulk') then + if (.not. tr_lvl) then + call icepack_warnings_add(subname//' ERROR: need lvl trcr') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + return + endif + hsnlvl = hsn / (c1 + snwlvlfac*(c1-alvln)) + ! snow volume over level ice + alvl = aicen * alvln + if (alvl > puny) then + vsn = hsnlvl * alvl + else + vsn = vsnon + alvl = aicen + endif + ! set snow properties over level ice + call shortwave_dEdd_set_snow(R_snw, & + dT_mlt, rsnw_mlt, & + alvl, vsn, & + Tsfcn, fsn, & + hs0, hsnlvl, & + rhosnwn(:), rsnwn(:), & + l_rsnows(:)) + if (icepack_warnings_aborted(subname)) return + endif ! snwredist + + fpn = c0 ! fraction of ice covered in pond + hpn = c0 ! pond depth over fpn + ! refrozen pond lid thickness avg over ice + ! allow snow to cover pond ice + ipn = apondn * ipndn + dhs = dhsn ! snow depth difference, sea ice - pond + if (.not. l_initonly .and. ipn > puny .and. & + dhs < puny .and. fsnow*dt > hs_min) & + dhs = hsnlvl - fsnow*dt ! initialize dhs>0 + spn = hsnlvl - dhs ! snow depth on pond ice + if (.not. l_initonly .and. ipn*spn < puny) dhs = c0 + dhsn = dhs ! save: constant until reset to 0 + + ! not using ipn assumes that lid ice is perfectly clear + ! if (ipn <= 0.3_dbl_kind) then + + ! fraction of ice area + fpn = apondn + ! pond depth over fraction fpn + hpn = hpndn + + ! reduce effective pond area absorbing surface heat flux + ! due to flux already having been used to melt pond ice + fpn = (c1 - ffracn) * fpn + + ! taper pond area with snow on pond ice + if (dhs > puny .and. spn >= puny .and. hs1 > puny) then + asnow = min(spn/hs1, c1) + fpn = (c1 - asnow) * fpn + endif + + ! infiltrate snow + hp = hpn + if (hp > puny) then + hs = hsnlvl + rp = rhofresh*hp/(rhofresh*hp + rhos*hs) + if (rp < p15) then + fpn = c0 + hpn = c0 + else + hmx = hs*(rhofresh - rhos)/rhofresh + tmp = max(c0, sign(c1, hp-hmx)) ! 1 if hp>=hmx, else 0 + hp = (rhofresh*hp + rhos*hs*tmp) & + / (rhofresh - rhos*(c1-tmp)) + hsn = hsn - hp*fpn*(c1-tmp) + hpn = hp * tmp + fpn = fpn * tmp + endif + endif ! hp > puny + + ! Zero out fraction of thin ponds for radiation only + if (hpn < hpmin) fpn = c0 + fsn = min(fsn, c1-fpn) + + ! endif ! masking by lid ice + apeffn = fpn ! for history + + end subroutine shortwave_dEdd_set_eff !======================================================================= ! @@ -3720,6 +3963,8 @@ subroutine icepack_step_radiation (dt, & yday, sec, & swvdr, swvdf, & swidr, swidf, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & coszen, fsnow, & alvdrn, alvdfn, & alidrn, alidfn, & @@ -3729,6 +3974,10 @@ subroutine icepack_step_radiation (dt, & fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswpenln, & Sswabsn, Iswabsn, & albicen, albsnon, & @@ -3748,6 +3997,12 @@ subroutine icepack_step_radiation (dt, & fsnow , & ! snowfall rate (kg/m^2 s) TLAT, TLON ! latitude and longitude (radian) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr , & ! sw down, uv dir (W/m^2) + swuvrdf , & ! sw down, uv dif (W/m^2) + swpardr , & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + integer (kind=int_kind), intent(in) :: & sec ! elapsed seconds into date @@ -3755,7 +4010,7 @@ subroutine icepack_step_radiation (dt, & yday ! day of the year character (len=char_len), intent(in), optional :: & - calendar_type ! differentiates Gregorian from other calendars + calendar_type ! differentiates proleptic_gregorian from other calendars integer (kind=int_kind), intent(in), optional :: & days_per_year ! number of days in one year @@ -3806,7 +4061,11 @@ subroutine icepack_step_radiation (dt, & fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) + fswthrun_uvrdr,& ! uv dir SW through ice to ocean (W/m^2) + fswthrun_uvrdf,& ! uv dif SW through ice to ocean (W/m^2) + fswthrun_pardr,& ! par dir SW through ice to ocean (W/m^2) + fswthrun_pardf ! par dif SW through ice to ocean (W/m^2) real (kind=dbl_kind), dimension(:,:), intent(inout) :: & fswpenln , & ! visible SW entering ice layers (W m-2) @@ -3844,6 +4103,16 @@ subroutine icepack_step_radiation (dt, & call icepack_warnings_setabort(.true.,__FILE__,__LINE__) return endif + if (semi_implicit_Tsfc) then + if (.not.(present(swuvrdr) .and. present(swuvrdf) .and. & + present(swpardr) .and. present(swpardf) .and. & + present(fswthrun_uvrdr) .and. present(fswthrun_uvrdf) .and. & + present(fswthrun_pardr) .and. present(fswthrun_pardf))) then + call icepack_warnings_add(subname//' ERROR: semi_implicit_Tsfc=T, missing arguments') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + return + endif + endif #ifdef CESMCOUPLED if (.not.present(days_per_year) .or. & .not.present(nextsw_cday) .or. & @@ -3912,11 +4181,19 @@ subroutine icepack_step_radiation (dt, & alvdrn, alvdfn, & alidrn, alidfn, & fswsfcn, fswintn, & + swuvrdr=swuvrdr, & + swuvrdf=swuvrdf, & + swpardr=swpardr, & + swpardf=swpardf, & fswthrun=fswthrun, & fswthrun_vdr=fswthrun_vdr, & fswthrun_vdf=fswthrun_vdf, & fswthrun_idr=fswthrun_idr, & fswthrun_idf=fswthrun_idf, & + fswthrun_uvrdr=fswthrun_uvrdr,& + fswthrun_uvrdf=fswthrun_uvrdf,& + fswthrun_pardr=fswthrun_pardr,& + fswthrun_pardf=fswthrun_pardf,& fswpenln=fswpenln, & Sswabsn=Sswabsn, & Iswabsn=Iswabsn, & @@ -3946,11 +4223,19 @@ subroutine icepack_step_radiation (dt, & alvdrn, alidrn, & alvdfn, alidfn, & fswsfcn, fswintn, & + swuvrdr=swuvrdr, & + swuvrdf=swuvrdf, & + swpardr=swpardr, & + swpardf=swpardf, & fswthrun=fswthrun, & fswthrun_vdr=fswthrun_vdr,& fswthrun_vdf=fswthrun_vdf,& fswthrun_idr=fswthrun_idr,& fswthrun_idf=fswthrun_idf,& + fswthrun_uvrdr=fswthrun_uvrdr,& + fswthrun_uvrdf=fswthrun_uvrdf,& + fswthrun_pardr=fswthrun_pardr,& + fswthrun_pardf=fswthrun_pardf,& fswpenl=fswpenln, & Iswabs=Iswabsn, & Sswabs=Sswabsn, & diff --git a/columnphysics/icepack_snow.F90 b/columnphysics/icepack_snow.F90 index 3987d292..1d10d95b 100644 --- a/columnphysics/icepack_snow.F90 +++ b/columnphysics/icepack_snow.F90 @@ -12,6 +12,7 @@ module icepack_snow 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: snw_growth_wet, drsnw_min, snwliq_max 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 @@ -31,9 +32,8 @@ module icepack_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.22e5_dbl_kind ! wet metamorphism parameter (um^3/s) - ! = 1.e18 * 4.22e-13 (Oleson 2010) + drsnw_min_o = 1.0186_dbl_kind ! Bun 1989 (um^3/s) + ! minimum volume growth rate 1.28x10^-8 mm^3/s/4/pi real (kind=dbl_kind) :: & min_rhos, & ! snowtable axis data, assumes linear data @@ -360,6 +360,9 @@ subroutine icepack_step_snow(dt, & hsn(n) = vsnon(n)/aicen(n) hin(n) = vicen(n)/aicen(n) endif + do k = 1, nslyr + rsnw (k,n) = max(rsnw_fall, rsnw(k,n)) + enddo enddo call update_snow_radius (dt, & @@ -843,6 +846,9 @@ subroutine update_snow_radius (dt, rsnw, hin, & drsnw_wet, & ! wet metamorphism (10^-6 m) drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m) + real (kind=dbl_kind) :: & + drsnw_dry_tmp ! snow grain radius growth (10^-6 m) + character (len=*),parameter :: subname='(update_snow_radius)' do n = 1, ncat @@ -867,7 +873,8 @@ subroutine update_snow_radius (dt, rsnw, hin, & 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)) + drsnw_dry_tmp = max(drsnw_dry(k), drsnw_min*drsnw_min_o/rsnw(k,n)**2*dt) + rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry_tmp + drsnw_wet(k)) enddo else ! hsn or hin < puny @@ -1102,7 +1109,7 @@ subroutine snow_wet_metamorph (dt, dr_wet, rsnw, smice, smliq) fliq = c1 if (smice + smliq > c0 .and. rsnw > c0) then fliq = min(smliq/(smice + smliq),p1) - dr_wet = S_wet * fliq**3*dt/(c4*pi*rsnw**2) + dr_wet = snw_growth_wet * fliq**3*dt/(c4*pi*rsnw**2) endif end subroutine snow_wet_metamorph @@ -1199,7 +1206,7 @@ subroutine drain_snow (vsnon, aicen, & 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) + dlout(k) = max(c0, (phi_liq(k) - snwliq_max * (c1-phi_ice(k))) * rhofresh * hslyr) massliq(k) = massliq(k) - dlout(k) if (k < nslyr) then dlin(k+1) = dlout(k) diff --git a/columnphysics/icepack_therm_bl99.F90 b/columnphysics/icepack_therm_bl99.F90 index 30c247ac..f9485e32 100644 --- a/columnphysics/icepack_therm_bl99.F90 +++ b/columnphysics/icepack_therm_bl99.F90 @@ -14,7 +14,7 @@ module icepack_therm_bl99 use icepack_kinds use icepack_parameters, only: c0, c1, c2, p1, p5, puny use icepack_parameters, only: rhoi, rhos, hs_min, cp_ice, cp_ocn, depressT, Lfresh, ksno, kice - use icepack_parameters, only: conduct, calc_Tsfc + use icepack_parameters, only: conduct, calc_Tsfc, semi_implicit_Tsfc use icepack_parameters, only: sw_redist, sw_frac, sw_dtemp use icepack_tracers, only: nilyr, nslyr use icepack_warnings, only: warnstr, icepack_warnings_add @@ -22,6 +22,8 @@ module icepack_therm_bl99 use icepack_therm_shared, only: ferrmax, l_brine use icepack_therm_shared, only: surface_heat_flux, dsurface_heat_flux_dTsf + use icepack_therm_shared, only: fsurf_cpl, flat_cpl, dfsurfdTs_cpl, dflatdTs_cpl + use icepack_therm_shared, only: fsurf_cpl0, flat_cpl0 implicit none @@ -211,6 +213,12 @@ subroutine temperature_changes (dt, & dflat_dT = c0 dflwout_dT = c0 einex = c0 + if (semi_implicit_Tsfc) then ! initialize + dfsurf_dT = dfsurfdTs_cpl + dflat_dT = dflatdTs_cpl + fsurfn = fsurf_cpl + flatn = flat_cpl + endif dt_rhoi_hlyr = dt / (rhoi*hilyr) ! hilyr > 0 if (hslyr > hs_min/real(nslyr,kind=dbl_kind)) & l_snow = .true. @@ -303,6 +311,10 @@ subroutine temperature_changes (dt, & endif + if (semi_implicit_Tsfc) then + fsurfn = fsurfn + fswsfc ! this is the total heat flux + endif + !----------------------------------------------------------------- ! Solve for new temperatures. ! Iterate until temperatures converge with minimal energy error. @@ -322,7 +334,7 @@ subroutine temperature_changes (dt, & !----------------------------------------------------------------- converged = .true. - dfsurf_dT = c0 + if (.not.semi_implicit_Tsfc) dfsurf_dT = c0 avg_Tsi = c0 enew = c0 einex = c0 @@ -353,21 +365,23 @@ subroutine temperature_changes (dt, & ! with respect to Tsf. !----------------------------------------------------------------- - ! surface heat flux - call surface_heat_flux(Tsf , fswsfc, & - rhoa , flw , & - potT , Qa , & - shcoef , lhcoef, & - flwoutn, fsensn, & - flatn , fsurfn) - if (icepack_warnings_aborted(subname)) return - - ! derivative of heat flux with respect to surface temperature - call dsurface_heat_flux_dTsf(Tsf , rhoa , & - shcoef , lhcoef , & - dfsurf_dT, dflwout_dT, & - dfsens_dT, dflat_dT ) - if (icepack_warnings_aborted(subname)) return + if (.not.semi_implicit_Tsfc) then ! no heat flux calculation + ! surface heat flux + call surface_heat_flux(Tsf , fswsfc, & + rhoa , flw , & + potT , Qa , & + shcoef , lhcoef, & + flwoutn, fsensn, & + flatn , fsurfn) + if (icepack_warnings_aborted(subname)) return + + ! derivative of heat flux with respect to surface temperature + call dsurface_heat_flux_dTsf(Tsf , rhoa , & + shcoef , lhcoef , & + dfsurf_dT, dflwout_dT, & + dfsens_dT, dflat_dT ) + if (icepack_warnings_aborted(subname)) return + endif !----------------------------------------------------------------- ! Compute conductive flux at top surface, fcondtopn. @@ -644,6 +658,9 @@ subroutine temperature_changes (dt, & !----------------------------------------------------------------- fsurfn = fsurfn + dTsf*dfsurf_dT + if (semi_implicit_Tsfc) then ! update lat hf based on dT + flatn = flatn + dTsf*dflat_dT + endif if (l_snow) then fcondtopn = kh(1) * (Tsf-zTsn(1)) else @@ -710,8 +727,15 @@ subroutine temperature_changes (dt, & call icepack_warnings_add(warnstr) write(warnstr,*) subname, 'fsurf:', fsurfn call icepack_warnings_add(warnstr) - write(warnstr,*) subname, 'fcondtop, fcondbot, fswint', & - fcondtopn, fcondbot, fswint + write(warnstr,*) subname, 'dfsurf_dT:', dfsurf_dT + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'enew:', enew + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'einit:', einit + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'dt:', dt + call icepack_warnings_add(warnstr) + write(warnstr,*) subname, 'fcondtop, fcondbot, fswint', fcondtopn, fcondbot, fswint call icepack_warnings_add(warnstr) write(warnstr,*) subname, 'fswsfc', fswsfc call icepack_warnings_add(warnstr) @@ -777,9 +801,11 @@ subroutine temperature_changes (dt, & if (calc_Tsfc) then ! update fluxes that depend on Tsf - flwoutn = flwoutn + dTsf_prev * dflwout_dT - fsensn = fsensn + dTsf_prev * dfsens_dT - flatn = flatn + dTsf_prev * dflat_dT + if (.not.semi_implicit_Tsfc) then + flwoutn = flwoutn + dTsf_prev * dflwout_dT + fsensn = fsensn + dTsf_prev * dfsens_dT + flatn = flatn + dTsf_prev * dflat_dT + endif endif ! calc_Tsfc diff --git a/columnphysics/icepack_therm_itd.F90 b/columnphysics/icepack_therm_itd.F90 index 0fcc9673..508d9ace 100644 --- a/columnphysics/icepack_therm_itd.F90 +++ b/columnphysics/icepack_therm_itd.F90 @@ -26,7 +26,7 @@ module icepack_therm_itd use icepack_parameters, only: c0, c1, c2, c3, c4, c6, c10 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, salt_loss + use icepack_parameters, only: phi_init, dsin0_frazil use icepack_parameters, only: Tliquidus_max use icepack_parameters, only: rhosi, conserv_check, rhosmin, snwredist use icepack_parameters, only: kitd, ktherm @@ -39,7 +39,7 @@ module icepack_therm_itd 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, nt_rhos, nt_sice use icepack_tracers, only: nt_alvl, nt_vlvl - use icepack_tracers, only: tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_lvl, tr_pond_topo, tr_pond 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 @@ -98,7 +98,8 @@ subroutine linear_itd (hin_max, trcr_depend, & aicen, trcrn, & vicen, vsnon, & aice, aice0, & - fpond, Tf ) + fpond, Tf, & + dpnd_melt) real (kind=dbl_kind), dimension(0:ncat), intent(in) :: & hin_max ! category boundaries (m) @@ -134,6 +135,9 @@ subroutine linear_itd (hin_max, trcr_depend, & aice0 , & ! concentration of open water fpond ! fresh water flux to ponds (kg/m^2/s) + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_melt ! pond 'drainage' due to ice melting (m / step) + ! local variables integer (kind=int_kind) :: & @@ -463,6 +467,14 @@ subroutine linear_itd (hin_max, trcr_depend, & if (tr_pond_topo) & fpond = fpond - (da0 * trcrn(nt_apnd,1) & * trcrn(nt_hpnd,1)) + if (tr_pond .and. present(dpnd_melt)) then + if (tr_pond_lvl) then + dpnd_melt = dpnd_melt + da0 * trcrn(nt_apnd,1) & + * trcrn(nt_hpnd,1) * trcrn(nt_alvl,1) + else + dpnd_melt = dpnd_melt + da0*trcrn(nt_apnd,1)*trcrn(nt_hpnd,1) + endif + endif endif ! etamax > 0 @@ -877,7 +889,8 @@ subroutine lateral_melt (dt, fpond, & wlat, & aicen, vicen, & vsnon, trcrn, & - flux_bio, d_afsd_latm) + flux_bio, d_afsd_latm,& + dpnd_melt) real (kind=dbl_kind), intent(in) :: & dt ! time step (s) @@ -903,6 +916,9 @@ subroutine lateral_melt (dt, fpond, & fhocn , & ! net heat flux to ocean (W/m^2) meltl ! lateral ice melt (m/step-->cm/day) + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_melt ! pond 'drainage' due to ice melting (m / step) + real (kind=dbl_kind), dimension(nbtrcr), intent(inout) :: & flux_bio ! biology tracer flux from layer bgc (mmol/m^2/s) @@ -1013,6 +1029,16 @@ subroutine lateral_melt (dt, fpond, & fpond = fpond - dfpond endif + if (tr_pond .and. present(dpnd_melt)) then + if (tr_pond_lvl) then + dpnd_melt = dpnd_melt + aicen(n)*trcrn(nt_apnd,n)*trcrn(nt_hpnd,n) & + *rsiden(n)*trcrn(nt_alvl,n) + else + dpnd_melt = dpnd_melt + aicen(n)*trcrn(nt_apnd,n)*trcrn(nt_hpnd,n) & + *rsiden(n) + endif + endif + ! history diagnostics meltl = meltl + vicen_init(n)*rsiden(n) @@ -1211,7 +1237,6 @@ subroutine add_new_ice (dt, & wave_sig_ht, & wave_spectrum, & wavefreq, & - dwavefreq, & d_afsd_latg, & d_afsd_newi) @@ -1284,8 +1309,7 @@ subroutine add_new_ice (dt, & wave_spectrum ! ocean surface wave spectrum, E(f) (m^2 s) real(kind=dbl_kind), dimension(:), intent(in), optional :: & - wavefreq, & ! wave frequencies (s^-1) - dwavefreq ! wave frequency bin widths (s^-1) + wavefreq ! wave frequencies (s^-1) real (kind=dbl_kind), dimension(:), intent(out), optional :: & ! change in thickness distribution (area) @@ -1715,7 +1739,6 @@ subroutine add_new_ice (dt, & wave_sig_ht, & wave_spectrum, & wavefreq, & - dwavefreq, & d_afsd_latg, & d_afsd_newi, & afsdn, aicen_init, & @@ -1860,7 +1883,7 @@ subroutine icepack_step_therm2(dt, hin_max, & fresh, fsalt, & fhocn, update_ocn_f, & faero_ocn, & - first_ice, fzsal, & + first_ice, & flux_bio, ocean_bio, & frazil_diag, & frz_onset, yday, & @@ -1869,9 +1892,9 @@ subroutine icepack_step_therm2(dt, hin_max, & wave_sig_ht, & wave_spectrum, & wavefreq, & - dwavefreq, & d_afsd_latg, d_afsd_newi, & - d_afsd_latm, d_afsd_weld) + d_afsd_latm, d_afsd_weld, & + dpnd_melt) use icepack_parameters, only: icepack_init_parameters @@ -1916,7 +1939,7 @@ subroutine icepack_step_therm2(dt, hin_max, & frazil_diag ! frazil ice growth diagnostic (m/step-->cm/day) real (kind=dbl_kind), intent(inout), optional :: & - fzsal ! salt flux to ocean from zsalinity (kg/m^2/s) (deprecated) + dpnd_melt ! pond 'drainage' due to ice melting (m / step) real (kind=dbl_kind), intent(in), optional :: & wlat ! lateral melt rate (m/s) @@ -1958,8 +1981,7 @@ subroutine icepack_step_therm2(dt, hin_max, & wave_spectrum ! ocean surface wave spectrum E(f) (m^2 s) real(kind=dbl_kind), dimension(:), intent(in), optional :: & - wavefreq, & ! wave frequencies (s^-1) - dwavefreq ! wave frequency bin widths (s^-1) + wavefreq ! wave frequencies (s^-1) real (kind=dbl_kind), dimension(:), intent(out), optional :: & ! change in floe size distribution (area) @@ -2000,7 +2022,6 @@ subroutine icepack_step_therm2(dt, hin_max, & present(wave_sig_ht) .and. & present(wave_spectrum) .and. & present(wavefreq) .and. & - present(dwavefreq) .and. & present(d_afsd_latg) .and. & present(d_afsd_newi) .and. & present(d_afsd_latm) .and. & @@ -2055,7 +2076,8 @@ subroutine icepack_step_therm2(dt, hin_max, & vsnon, & aice , & aice0 , & - fpond, Tf ) + fpond, Tf , & + dpnd_melt) if (icepack_warnings_aborted(subname)) return endif ! aice > puny @@ -2087,8 +2109,7 @@ subroutine icepack_step_therm2(dt, hin_max, & HDO_ocn, H2_16O_ocn, & H2_18O_ocn, & wave_sig_ht, & - wave_spectrum, & - wavefreq, dwavefreq, & + wave_spectrum, wavefreq, & d_afsd_latg, d_afsd_newi) if (icepack_warnings_aborted(subname)) return @@ -2106,7 +2127,7 @@ subroutine icepack_step_therm2(dt, hin_max, & aicen, vicen, & vsnon, trcrn, & flux_bio, & - d_afsd_latm) + d_afsd_latm, dpnd_melt) if (icepack_warnings_aborted(subname)) return ! Floe welding during freezing conditions @@ -2126,7 +2147,8 @@ subroutine icepack_step_therm2(dt, hin_max, & if (ncat==1) & call reduce_area (hin_max (0), & aicen (1), vicen (1), & - aicen_init(1), vicen_init(1)) + aicen_init(1), vicen_init(1), & + dpnd_melt , trcrn) if (icepack_warnings_aborted(subname)) return !----------------------------------------------------------------- diff --git a/columnphysics/icepack_therm_mushy.F90 b/columnphysics/icepack_therm_mushy.F90 index 00438e8d..7e5b698e 100644 --- a/columnphysics/icepack_therm_mushy.F90 +++ b/columnphysics/icepack_therm_mushy.F90 @@ -5,12 +5,13 @@ module icepack_therm_mushy use icepack_kinds 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, snwgrain + use icepack_parameters, only: viscosity_dyn, rhow, rhoi, rhos, cp_ocn, cp_ice, Lfresh, gravit, rhofresh + use icepack_parameters, only: hs_min, snwgrain, semi_implicit_Tsfc use icepack_parameters, only: a_rapid_mode, Rac_rapid_mode, tscale_pnd_drain use icepack_parameters, only: aspect_rapid_mode, dSdt_slow_mode, phi_c_slow_mode use icepack_parameters, only: sw_redist, sw_frac, sw_dtemp - use icepack_tracers, only: nilyr, nslyr, tr_pond + use icepack_parameters, only: pndmacr + use icepack_tracers, only: nilyr, nslyr, tr_pond, tr_pond_sealvl use icepack_mushy_physics, only: icepack_mushy_density_brine, enthalpy_brine, icepack_enthalpy_snow use icepack_mushy_physics, only: enthalpy_mush_liquid_fraction use icepack_mushy_physics, only: icepack_mushy_temperature_mush, icepack_mushy_liquid_fraction @@ -19,6 +20,9 @@ module icepack_therm_mushy use icepack_mushy_physics, only: conductivity_mush_array, conductivity_snow_array use icepack_therm_shared, only: surface_heat_flux, dsurface_heat_flux_dTsf use icepack_therm_shared, only: ferrmax + use icepack_meltpond_sealvl, only: pond_hypsometry, pond_height + use icepack_therm_shared, only: fsurf_cpl, flat_cpl, dfsurfdTs_cpl, dflatdTs_cpl + use icepack_therm_shared, only: fsurf_cpl0, flat_cpl0 use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -56,7 +60,9 @@ subroutine temperature_changes_salinity(dt, & flwoutn, fsurfn, & fcondtop, fcondbot, & fadvheat, snoice, & - smice, smliq) + smice, smliq, & + dpnd_flush, & + dpnd_expon) ! solve the enthalpy and bulk salinity of the ice for a single column @@ -80,7 +86,7 @@ subroutine temperature_changes_salinity(dt, & real (kind=dbl_kind), intent(inout) :: & hilyr , & ! ice layer thickness (m) hslyr , & ! snow layer thickness (m) - apond , & ! melt pond area fraction + apond , & ! melt pond area fraction of category hpond ! melt pond depth (m) real (kind=dbl_kind), dimension (:), intent(inout) :: & @@ -111,6 +117,10 @@ subroutine temperature_changes_salinity(dt, & zqsn , & ! snow layer enthalpy (J m-3) zTsn ! internal snow layer temperatures + real (kind=dbl_kind), intent(inout):: & + dpnd_flush , & ! pond flushing rate due to ice permeability (m/s) + dpnd_expon ! exponential pond drainage rate (m/s) + ! local variables real(kind=dbl_kind), dimension(1:nilyr) :: & zqin0 , & ! ice layer enthalpy (J m-3) at start of timestep @@ -328,7 +338,8 @@ subroutine temperature_changes_salinity(dt, & endif ! drain ponds from flushing - call flush_pond(w, hpond, apond, dt) + call flush_pond(w, hpond, apond, dt, dpnd_flush, dpnd_expon, & + zTin, phi, hilyr, hin, hsn) if (icepack_warnings_aborted(subname)) return ! flood snow ice @@ -841,6 +852,11 @@ subroutine two_stage_solver_nosnow(Tsf, Tsf0, & else ! initially melting + if (semi_implicit_Tsfc) then ! update surf/lat hf based on dT + fsurf_cpl = fsurf_cpl + dfsurfdTs_cpl * (Tmlt - Tsf) + flat_cpl = flat_cpl + dflatdTs_cpl * (Tmlt - Tsf) + endif + ! solve the system for melt and no snow Tsf = Tmlt @@ -885,6 +901,11 @@ subroutine two_stage_solver_nosnow(Tsf, Tsf0, & fcondtop1 = fcondtop fsurfn1 = fsurfn + if (semi_implicit_Tsfc) then ! initialize + fsurf_cpl = fsurf_cpl0 + flat_cpl = flat_cpl0 + endif + ! reset the solution to initial values Tsf = Tsf0 zqin = zqin0 @@ -1226,24 +1247,36 @@ subroutine picard_solver(lsnow, lcold, & zTsn_prev = zTsn zTin_prev = zTin + if (semi_implicit_Tsfc) then ! surf/lat hf from coupler, d(surf/lat)/dT computed + dfsurfn_dTsf = dfsurfdTs_cpl + dflatn_dTsf = dflatdTs_cpl + fsurfn = fsurf_cpl + flatn = flat_cpl + fsurfn = fsurfn + fswsfc + flwoutn = c0 !prevent compiler warning + fsensn = c0 !prevent compiler warning + endif + ! picard iteration picard: do nit = 1, nit_max - ! surface heat flux - call surface_heat_flux(Tsf, fswsfc, & - rhoa, flw, & - potT, Qa, & - shcoef, lhcoef, & - flwoutn, fsensn, & - flatn, fsurfn) - if (icepack_warnings_aborted(subname)) return + if (.not.semi_implicit_Tsfc) then ! no surface heat flux calculation + ! surface heat flux + call surface_heat_flux(Tsf, fswsfc, & + rhoa, flw, & + potT, Qa, & + shcoef, lhcoef, & + flwoutn, fsensn, & + flatn, fsurfn) + if (icepack_warnings_aborted(subname)) return - ! derivative of heat flux with respect to surface temperature - call dsurface_heat_flux_dTsf(Tsf, rhoa, & - shcoef, lhcoef, & - dfsurfn_dTsf, dflwoutn_dTsf, & - dfsensn_dTsf, dflatn_dTsf) - if (icepack_warnings_aborted(subname)) return + ! derivative of heat flux with respect to surface temperature + call dsurface_heat_flux_dTsf(Tsf, rhoa, & + shcoef, lhcoef, & + dfsurfn_dTsf, dflwoutn_dTsf, & + dfsensn_dTsf, dflatn_dTsf) + if (icepack_warnings_aborted(subname)) return + endif ! tridiagonal solve of new temperatures call solve_heat_conduction(lsnow, lcold, & @@ -1289,6 +1322,11 @@ subroutine picard_solver(lsnow, lcold, & fadvheat_nit) if (icepack_warnings_aborted(subname)) return + if (semi_implicit_Tsfc) then ! update surf/lat hf based on dT + fsurfn = fsurfn + (Tsf - Tsf_prev)*dfsurfn_dTsf + flatn = flatn + (Tsf - Tsf_prev)*dflatn_dTsf + endif + if (lconverged) exit Tsf_prev = Tsf @@ -1312,13 +1350,15 @@ subroutine picard_solver(lsnow, lcold, & if (icepack_warnings_aborted(subname)) return ! final surface heat flux - call surface_heat_flux(Tsf, fswsfc, & - rhoa, flw, & - potT, Qa, & - shcoef, lhcoef, & - flwoutn, fsensn, & - flatn, fsurfn) - if (icepack_warnings_aborted(subname)) return + if (.not.semi_implicit_Tsfc) then ! no surface heat flux calculation + call surface_heat_flux(Tsf, fswsfc, & + rhoa, flw, & + potT, Qa, & + shcoef, lhcoef, & + flwoutn, fsensn, & + flatn, fsurfn) + if (icepack_warnings_aborted(subname)) return + endif ! if not converged if (.not. lconverged) then @@ -3077,7 +3117,7 @@ subroutine flushing_velocity(zTin, phi, & real(kind=dbl_kind), intent(in) :: & hilyr , & ! ice layer thickness (m) hpond , & ! melt pond thickness (m) - apond , & ! melt pond area (-) + apond , & ! melt pond area fraction of category (-) hsn , & ! snow thickness (m) hin , & ! ice thickness (m) dt ! time step (s) @@ -3121,13 +3161,13 @@ subroutine flushing_velocity(zTin, phi, & !phi = icepack_mushy_liquid_fraction(zTin(k), zSin(k)) phi_min = min(phi_min,phi(k)) + ice_mass = ice_mass + phi(k) * & + icepack_mushy_density_brine( & + liquidus_brine_salinity_mush(zTin(k))) + (c1 - phi(k))*rhoi + ! permeability perm = permeability(phi(k)) - ! ice mass - ice_mass = ice_mass + phi(k) * icepack_mushy_density_brine(liquidus_brine_salinity_mush(zTin(k))) + & - (c1 - phi(k)) * rhoi - ! permeability harmonic mean perm_harm = perm_harm + c1 / (perm + 1e-30_dbl_kind) @@ -3138,10 +3178,15 @@ subroutine flushing_velocity(zTin, phi, & perm_harm = real(nilyr,dbl_kind) / perm_harm ! calculate ocean surface height above bottom of ice - hocn = (ice_mass + hpond * apond * rhow + hsn * rhos) / rhow + hocn = (ice_mass + hpond * apond * rhofresh + hsn * rhos) / rhow ! calculate brine height above bottom of ice - hbrine = hin + hpond + if (tr_pond_sealvl) then + call pond_height(apond, hpond, hin, hbrine) + if (icepack_warnings_aborted(subname)) return + else + hbrine = hin + hpond + endif ! pressure head dhhead = max(hbrine - hocn,c0) @@ -3172,17 +3217,34 @@ end subroutine flushing_velocity !======================================================================= - subroutine flush_pond(w, hpond, apond, dt) + subroutine flush_pond(w, hpond, apond, dt, dpnd_flush, dpnd_expon, & + zTin, phi, hilyr, hin, hsn) ! given a flushing velocity drain the meltponds real(kind=dbl_kind), intent(in) :: & w , & ! vertical flushing Darcy flow rate (m s-1) - apond , & ! melt pond area (-) - dt ! time step (s) + dt , & ! time step (s) + hilyr , & ! ice layer thickness (m) + hin , & ! ice thickness (m) + hsn ! snow thickness (m) + + real(kind=dbl_kind), dimension(:), intent(in) :: & + zTin , & ! ice layer temperature (C) + phi ! ice layer liquid fraction real(kind=dbl_kind), intent(inout) :: & - hpond ! melt pond thickness (m) + hpond , & ! melt pond thickness (m) + apond , & ! melt pond area fraction of category (-) + dpnd_flush, & ! pond flushing rate due to ice permeability (m/s) + dpnd_expon ! exponential pond drainage rate (m/s) + + real(kind=dbl_kind) :: & + dhpond , & ! change in pond depth per unit pond area (m) + ice_mass , & ! mass of ice (kg m-2) + hocn , & ! height of ocean above mean base of ice (m) + hpsurf , & ! height of the pond surface above mean base of ice (m) + head ! height of pond surface above sea level (m) real(kind=dbl_kind), parameter :: & hpond0 = 0.01_dbl_kind @@ -3194,18 +3256,58 @@ subroutine flush_pond(w, hpond, apond, dt) if (tr_pond) then if (apond > c0 .and. hpond > c0) then - - ! flush pond through mush - hpond = hpond - w * dt / apond - + !------------------------------------------------------------- + ! flush pond through mush (percolation drainage) + !------------------------------------------------------------- + dhpond = max(-w * dt / apond, -hpond) + dpnd_flush = -dhpond * apond + ! update pond depth (and area) + if (tr_pond_sealvl) then + call pond_hypsometry(hpond, apond, dhpond=dhpond, hin=hin) + if (icepack_warnings_aborted(subname)) return + else + hpond = hpond - w * dt / apond + endif hpond = max(hpond, c0) - ! exponential decay of pond - lambda_pond = c1 / (tscale_pnd_drain * 24.0_dbl_kind * 3600.0_dbl_kind) - hpond = hpond - lambda_pond * dt * (hpond + hpond0) - + !------------------------------------------------------------- + ! exponential decay of pond (macro-flaw drainage) + !------------------------------------------------------------- + lambda_pond = c1 / (tscale_pnd_drain*24.0_dbl_kind & + *3600.0_dbl_kind) + if (trim(pndmacr) == 'lambda') then + dhpond = max(-lambda_pond*dt*(hpond + hpond0),-hpond) + elseif (trim(pndmacr) == 'head') then + ! Calling calc_ice_mass here is not bit-for-bit due to optimization, so left inline for now. + ! This will be updated in the future. + call calc_ice_mass(phi, zTin, hilyr, ice_mass) + if (icepack_warnings_aborted(subname)) return + hocn = (ice_mass + hpond*apond*rhofresh + hsn*rhos)/rhow + call pond_height(apond, hpond, hin, hpsurf) + if (icepack_warnings_aborted(subname)) return + head = hpsurf - hocn + dhpond = max(min(c0, -lambda_pond*dt*head), -hpond) + else + call icepack_warnings_add(subname//" unsupported pndmacr option" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + ! diagnostic drainage rate + dpnd_expon = -dhpond * apond + ! update pond depth (and area) + if (tr_pond_sealvl) then + call pond_hypsometry(hpond, apond, dhpond=dhpond, hin=hin) + if (icepack_warnings_aborted(subname)) return + else + if (trim(pndmacr) == 'lambda') then + hpond = hpond - lambda_pond * dt * (hpond + hpond0) + else + call icepack_warnings_add(subname//" currently only pondmacr='lambda' supported for not sealvlponds" ) + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + if (icepack_warnings_aborted(subname)) return + endif + endif hpond = max(hpond, c0) - endif endif @@ -3574,6 +3676,41 @@ subroutine update_vertical_tracers_ice(trc, hlyr1, hlyr2, & end subroutine update_vertical_tracers_ice +!======================================================================= +! Ice Mass +!======================================================================= + + subroutine calc_ice_mass(phi, zTin, hilyr, ice_mass) + + ! Calculate the mass of the ice per unit category area + real(kind=dbl_kind), dimension(:), intent(in) :: & + zTin , & ! ice layer temperature (C) + phi ! ice layer liquid fraction + + real(kind=dbl_kind), intent(in) :: & + hilyr ! ice layer thickness (m) + + real(kind=dbl_kind), intent(out) :: & + ice_mass ! mass per unit category area (kg m-2) + + ! local variables + integer(kind=int_kind) :: & + k ! ice layer index + + character(len=*),parameter :: subname='(calc_ice_mass)' + + ice_mass = c0 + + do k = 1, nilyr + ice_mass = ice_mass + phi(k) * & + icepack_mushy_density_brine( & + liquidus_brine_salinity_mush(zTin(k))) + (c1 - phi(k))*rhoi + enddo + + ice_mass = ice_mass * hilyr + +end subroutine calc_ice_mass + !======================================================================= end module icepack_therm_mushy diff --git a/columnphysics/icepack_therm_shared.F90 b/columnphysics/icepack_therm_shared.F90 index 858e6c56..73d560b6 100644 --- a/columnphysics/icepack_therm_shared.F90 +++ b/columnphysics/icepack_therm_shared.F90 @@ -48,6 +48,14 @@ module icepack_therm_shared logical (kind=log_kind), public :: & l_brine ! if true, treat brine pocket effects + real (kind=dbl_kind), public :: & + dfsurfdTs_cpl, & ! + dflatdTs_cpl, & ! + fsurf_cpl0, & ! + flat_cpl0, & ! + fsurf_cpl, & ! + flat_cpl ! + !======================================================================= contains diff --git a/columnphysics/icepack_therm_vertical.F90 b/columnphysics/icepack_therm_vertical.F90 index a0aa6b84..00b3756d 100644 --- a/columnphysics/icepack_therm_vertical.F90 +++ b/columnphysics/icepack_therm_vertical.F90 @@ -30,17 +30,19 @@ module icepack_therm_vertical use icepack_parameters, only: ustar_min, fbot_xfer_type, formdrag, calc_strair 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_parameters, only: saltflux_option, congel_freeze + use icepack_parameters, only: saltflux_option, congel_freeze, semi_implicit_Tsfc, vapor_flux_correction use icepack_parameters, only: icepack_chkoptargflag use icepack_tracers, only: ncat, nilyr, nslyr, nfsd use icepack_tracers, only: tr_iage, tr_FY, tr_aero, tr_pond, tr_fsd, tr_iso - use icepack_tracers, only: tr_pond_lvl, tr_pond_topo + use icepack_tracers, only: tr_pond_lvl, tr_pond_topo, tr_pond_sealvl use icepack_tracers, only: n_aero, n_iso use icepack_therm_shared, only: ferrmax, l_brine use icepack_therm_shared, only: calculate_tin_from_qin, Tmin use icepack_therm_shared, only: adjust_enthalpy + use icepack_therm_shared, only: fsurf_cpl, flat_cpl, dfsurfdTs_cpl, dflatdTs_cpl + use icepack_therm_shared, only: fsurf_cpl0, flat_cpl0 use icepack_therm_bl99, only: temperature_changes use icepack_therm_mushy, only: temperature_changes_salinity @@ -60,6 +62,7 @@ module icepack_therm_vertical use icepack_flux, only: set_sfcflux, merge_fluxes use icepack_meltpond_lvl, only: compute_ponds_lvl use icepack_meltpond_topo, only: compute_ponds_topo + use icepack_meltpond_sealvl, only: compute_ponds_sealvl use icepack_snow, only: drain_snow implicit none @@ -107,7 +110,8 @@ subroutine thermo_vertical (dt, aicen, & congel, snoice, & mlt_onset, frz_onset, & yday, dsnow, & - prescribed_ice) + prescribed_ice, & + dpnd_flush, dpnd_expon) real (kind=dbl_kind), intent(in) :: & dt , & ! time step @@ -122,7 +126,7 @@ subroutine thermo_vertical (dt, aicen, & ! tracers real (kind=dbl_kind), intent(inout) :: & Tsf , & ! ice/snow top surface temp, same as Tsfcn (deg C) - apond , & ! melt pond area fraction + apond , & ! melt pond area fraction of category hpond ! melt pond depth (m) ! iage ! ice age (s) @@ -199,7 +203,9 @@ subroutine thermo_vertical (dt, aicen, & snoice , & ! snow-ice formation (m/step-->cm/day) dsnow , & ! change in snow thickness (m/step-->cm/day) mlt_onset, & ! day of year that sfc melting begins - frz_onset ! day of year that freezing begins (congel or frazil) + frz_onset, & ! day of year that freezing begins (congel or frazil) + dpnd_flush,& ! pond flushing rate due to ice permeability (m/s) + dpnd_expon ! exponential pond drainage rate (m/s) real (kind=dbl_kind), intent(in) :: & yday ! day of year @@ -266,9 +272,13 @@ subroutine thermo_vertical (dt, aicen, & meltsliq= c0 massice(:) = c0 massliq(:) = c0 + if (tr_pond) then + dpnd_flush = c0 + dpnd_expon = c0 + endif if (calc_Tsfc) then - fsensn = c0 + fsensn = c0 flatn = c0 fsurfn = c0 fcondtopn = c0 @@ -324,7 +334,8 @@ subroutine thermo_vertical (dt, aicen, & flwoutn, fsurfn, & fcondtopn, fcondbotn, & fadvocn, snoice, & - smice, smliq) + smice, smliq, & + dpnd_flush,dpnd_expon) if (icepack_warnings_aborted(subname)) return else ! ktherm @@ -342,7 +353,7 @@ subroutine thermo_vertical (dt, aicen, & Tsf, Tbot, & fsensn, flatn, & flwoutn, fsurfn, & - fcondtopn, fcondbotn, & + fcondtopn, fcondbotn, & einit ) if (icepack_warnings_aborted(subname)) return @@ -364,12 +375,11 @@ subroutine thermo_vertical (dt, aicen, & einter = einter + hilyr * zqin(k) enddo ! k - Tsnice = c0 - if ((hslyr+hilyr) > puny) then + if (hilyr > puny) then if (hslyr > puny) then - Tsnice = (hslyr*zTsn(nslyr) + hilyr*zTin(1)) / (hslyr+hilyr) + Tsnice = Tsnice + aicen*((hilyr*zTsn(nslyr) + hslyr*zTin(1)) / (hslyr+hilyr)) else - Tsnice = Tsf + Tsnice = Tsnice + aicen*Tsf endif endif @@ -1154,7 +1164,8 @@ subroutine thickness_changes (dt, yday, & wk1 , & ! temporary variable zqsnew , & ! enthalpy of new snow (J m-3) hstot , & ! snow thickness including new snow (m) - Tmlts ! melting temperature (deg C) + Tmlts , & ! melting temperature (deg C) + de_vapor ! energy correction due to cond/sub inconsistency (J m-2) real (kind=dbl_kind), dimension (nilyr+1) :: & zi1 , & ! depth of ice layer boundaries (m) @@ -1191,6 +1202,7 @@ subroutine thickness_changes (dt, yday, & dhi = c0 dhs = c0 hsn_new = c0 + de_vapor = c0 do k = 1, nilyr dzi(k) = hilyr @@ -1275,21 +1287,53 @@ subroutine thickness_changes (dt, yday, & evapin = c0 ! initialize if (hsn > puny) then ! add snow with enthalpy zqsn(1) - dhs = econ / (zqsn(1) - rhos*Lvap) ! econ < 0, dhs > 0 - ! assume all condensation becomes ice (no liquid) - massice(1) = massice(1) + dhs*rhos + if (vapor_flux_correction) then ! compute mass/enthalpy at 0C + dhs = econ / (-rhos*Lfresh - rhos*Lvap) ! econ < 0, dhs > 0 + + ! assume all condensation becomes ice (no liquid) + massice(1) = massice(1) + dhs*rhos + + hstot = dzs(1) + dhs + ! adjust top layer snow enthalpy b.c. we added them at 0C + zqsnew = -rhos*Lfresh + if (hstot > puny) then + zqsn(1) = (dzs(1) * zqsn(1) & + + dhs * zqsnew) / hstot + if (ktherm < 2) then + ! avoid roundoff errors + zqsn(1) = min(zqsn(1), -rhos*Lfresh) + endif + endif + else + dhs = econ / (zqsn(1) - rhos*Lvap) ! econ < 0, dhs > 0 + + ! assume all condensation becomes ice (no liquid) + massice(1) = massice(1) + dhs*rhos + endif dzs(1) = dzs(1) + dhs evapn = evapn + dhs*rhos evapsn = evapsn + dhs*rhos + else ! add ice with enthalpy zqin(1) - dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 + + if (vapor_flux_correction) then ! compute mass/enthalpy at 0C + dhi = econ / (-rhoi*Lfresh - rhoi*Lvap) ! econ < 0, dhi > 0 + ! adjust top layer ice enthalpy b.c. we added them at 0C + !zqsnew = -rhoi*Lfresh + !hqtot = dzi(1)*qm(1) + dhi*zqsnew + de_vapor = de_vapor + (-dhi)*(qm(1) - (-rhoi*Lfresh)) ! de_vapor can be v+- (J m-2) + else + dhi = econ / (qm(1) - rhoi*Lvap) ! econ < 0, dhi > 0 + endif + dzi(1) = dzi(1) + dhi evapn = evapn + dhi*rhoi evapin = evapin + dhi*rhoi ! enthalpy of melt water emlt_atm = emlt_atm - qmlt(1) * dhi + endif !-------------------------------------------------------------- @@ -1389,8 +1433,14 @@ subroutine thickness_changes (dt, yday, & ! Sublimation of snow (evapn < 0) !-------------------------------------------------------------- - qsub = zqsn(k) - rhos*Lvap ! qsub < 0 - dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 + if (vapor_flux_correction) then ! compute mass/enthalpy and de_vapor correction + qsub = -rhos*Lfresh - rhos*Lvap ! qsub < 0 + dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 + de_vapor = de_vapor + (-dhs)*min(zqsn(k) - (-rhos*Lfresh), c0) ! de_vapor < 0 (J m-2) + else + qsub = zqsn(k) - rhos*Lvap ! qsub < 0 + dhs = max (-dzs(k), esub/qsub) ! esub > 0, dhs < 0 + endif mass = massice(k) + massliq(k) massi = c0 @@ -1776,6 +1826,9 @@ subroutine thickness_changes (dt, yday, & ! sublimated/condensed ice. !----------------------------------------------------------------- + if (vapor_flux_correction) then ! update fhocnn based on de_vapor correction + fhocnn = fhocnn + de_vapor/dt + endif efinal = -evapn*Lvap evapn = evapn/dt evapsn = evapsn/dt @@ -2166,6 +2219,10 @@ subroutine icepack_step_therm1(dt, & fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswabs , & flwout , & Sswabsn , Iswabsn , & @@ -2181,8 +2238,13 @@ subroutine icepack_step_therm1(dt, & fswthru_vdf , & fswthru_idr , & fswthru_idf , & + fswthru_uvrdr , & + fswthru_uvrdf , & + fswthru_pardr , & + fswthru_pardf , & flatn_f , fsensn_f , & fsurfn_f , fcondtopn_f , & + dfsurfdT , dflatdT , & faero_atm , faero_ocn , & fiso_atm , fiso_ocn , & fiso_evap , & @@ -2201,7 +2263,12 @@ subroutine icepack_step_therm1(dt, & lmask_n , lmask_s , & mlt_onset , frz_onset , & yday , prescribed_ice, & - zlvs , afsdn) + zlvs , afsdn , & + dpnd_flush , dpnd_flushn , & + dpnd_expon , dpnd_exponn , & + dpnd_freebd , dpnd_freebdn, & + dpnd_initial, dpnd_initialn, & + dpnd_dlid , dpnd_dlidn) real (kind=dbl_kind), intent(in) :: & dt , & ! time step @@ -2288,6 +2355,13 @@ subroutine icepack_step_therm1(dt, & mlt_onset , & ! day of year that sfc melting begins frz_onset ! day of year that freezing begins (congel or frazil) + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_flush , & ! pond flushing rate due to ice permeability (m/step) + dpnd_expon , & ! exponential pond drainage rate (m/step) + dpnd_freebd , & ! pond drainage rate due freeboard constraint (m/step) + dpnd_initial, & ! runoff rate due to rfrac (m/step) + dpnd_dlid ! pond loss/gain (+/-) to ice lid (m/step) + real (kind=dbl_kind), intent(out), optional :: & wlat ! lateral melt rate (m/s) @@ -2296,6 +2370,10 @@ subroutine icepack_step_therm1(dt, & 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_uvrdr,& ! uv dir shortwave penetrating to ocean (W/m^2) + fswthru_uvrdf,& ! uv dif shortwave penetrating to ocean (W/m^2) + fswthru_pardr,& ! par dir shortwave penetrating to ocean (W/m^2) + fswthru_pardf,& ! par dif shortwave penetrating to ocean (W/m^2) dsnow , & ! change in snow depth (m/step-->cm/day) fsloss ! rate of snow loss to leads (kg/m^2/s) @@ -2336,7 +2414,7 @@ subroutine icepack_step_therm1(dt, & Tsfc , & ! ice/snow surface temperature, Tsfcn alvl , & ! level ice area fraction vlvl , & ! level ice volume fraction - apnd , & ! melt pond area fraction + apnd , & ! melt pond area fraction tracer hpnd , & ! melt pond depth (m) ipnd , & ! melt pond refrozen lid thickness (m) iage , & ! volume-weighted ice age @@ -2363,6 +2441,13 @@ subroutine icepack_step_therm1(dt, & congeln , & ! congelation ice growth (m) snoicen ! snow-ice growth (m) + real (kind=dbl_kind), dimension(:), intent(inout), optional :: & + dpnd_flushn , & ! category pond flushing rate (m/step) + dpnd_exponn , & ! exponential pond drainage rate (m/step) + dpnd_freebdn, & ! pond drainage rate due to freeboard (m/step) + dpnd_initialn,& ! runoff rate due to rfrac (m/step) + dpnd_dlidn ! category pond loss/gain due to ice lid (m/step) + real (kind=dbl_kind), dimension(:), intent(in) :: & fswthrun ! SW through ice to ocean (W/m^2) @@ -2370,10 +2455,16 @@ subroutine icepack_step_therm1(dt, & dsnown ! change in snow thickness (m/step-->cm/day) real (kind=dbl_kind), dimension(:), intent(in), optional :: & + dfsurfdT , & ! derivative of fsurfn with respect to temperatur (W m-2 K-1) + dflatdT , & ! derivative of flatn with respect to temperature (W m-2 K-1) fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) + fswthrun_uvrdr,& ! uv dir SW through ice to ocean (W/m^2) + fswthrun_uvrdf,& ! uv dif SW through ice to ocean (W/m^2) + fswthrun_pardr,& ! par dir SW through ice to ocean (W/m^2) + fswthrun_pardf ! par dif SW through ice to ocean (W/m^2) real (kind=dbl_kind), dimension(:,:), intent(inout) :: & zqsn , & ! snow layer enthalpy (J m-3) @@ -2437,16 +2528,28 @@ subroutine icepack_step_therm1(dt, & smliq ! tracer for mass of liquid in snow (kg/m^3) real (kind=dbl_kind), dimension(ncat) :: & + apond , & ! melt pond area fraction of category l_meltsliqn ! mass of snow melt local (kg/m^2) real (kind=dbl_kind) :: & - l_fswthrun_vdr, & ! vis dir SW local n ice to ocean (W/m^2) - l_fswthrun_vdf, & ! vis dif SW local n ice to ocean (W/m^2) - l_fswthrun_idr, & ! nir dir SW local n ice to ocean (W/m^2) - l_fswthrun_idf, & ! nir dif SW local n ice to ocean (W/m^2) - l_dsnow, & ! local snow change - l_dsnown, & ! local snow change category - l_meltsliq ! mass of snow melt local (kg/m^2) + l_fswthrun_vdr, & ! vis dir SW category ice to ocean (W/m^2) + l_fswthrun_vdf, & ! vis dif SW category ice to ocean (W/m^2) + l_fswthrun_idr, & ! nir dir SW category ice to ocean (W/m^2) + l_fswthrun_idf, & ! nir dif SW category ice to ocean (W/m^2) + l_fswthrun_uvrdr, & ! uv dir SW category ice to ocean (W/m^2) + l_fswthrun_uvrdf, & ! uv dif SW category ice to ocean (W/m^2) + l_fswthrun_pardr, & ! par dir SW category ice to ocean (W/m^2) + l_fswthrun_pardf, & ! par dif SW category ice to ocean (W/m^2) + l_dsnow, & ! local snow change + l_dsnown, & ! local snow change category + l_meltsliq ! mass of snow melt local (kg/m^2) + + real (kind=dbl_kind) :: & + l_dpnd_flushn, & ! category pond flushing rate (m/step) + l_dpnd_exponn, & ! exponential pond drainage rate (m/step) + l_dpnd_freebdn, & ! pond drainage rate due to freeboard (m/step) + l_dpnd_initialn,& ! runoff rate due to rfrac (m/step) + l_dpnd_dlidn ! category pond loss/gain due to ice lid (m/step) real (kind=dbl_kind) :: & pond ! water retained in ponds (m) @@ -2489,8 +2592,40 @@ subroutine icepack_step_therm1(dt, & call icepack_warnings_setabort(.true.,__FILE__,__LINE__) return endif - if ((present(dsnow) .and. .not.present(dsnown)) .or. & - (present(dsnown) .and. .not.present(dsnow))) then + if (semi_implicit_Tsfc) then + if (.not.(present(fswthru_uvrdr) .and. present(fswthru_uvrdf) .and. & + present(fswthru_pardr) .and. present(fswthru_pardf) .and. & + present(dfsurfdT) .and. present(dflatdT) )) then + call icepack_warnings_add(subname//' error in semi_implicit_Tsfc arguments, semi_implicit_Tsfc=T') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + endif + endif + if ((present(fswthru_uvrdr) .and. .not.present(fswthrun_uvrdr)) .or. & + (present(fswthru_uvrdf) .and. .not.present(fswthrun_uvrdf)) .or. & + (present(fswthru_pardr) .and. .not.present(fswthrun_pardr)) .or. & + (present(fswthru_pardf) .and. .not.present(fswthrun_pardf))) then + call icepack_warnings_add(subname//' error in fswthru [uvr|par]d[rf] arguments') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + return + endif + if (tr_pond) then + if ((present(dpnd_flushn ) .and. .not.present(dpnd_flush )) .or. & + (present(dpnd_flush ) .and. .not.present(dpnd_flushn )) .or. & + (present(dpnd_exponn ) .and. .not.present(dpnd_expon )) .or. & + (present(dpnd_expon ) .and. .not.present(dpnd_exponn )) .or. & + (present(dpnd_freebdn ) .and. .not.present(dpnd_freebd )) .or. & + (present(dpnd_freebd ) .and. .not.present(dpnd_freebdn )) .or. & + (present(dpnd_initialn) .and. .not.present(dpnd_initial )) .or. & + (present(dpnd_initial ) .and. .not.present(dpnd_initialn)) .or. & + (present(dpnd_dlidn ) .and. .not.present(dpnd_dlid )) .or. & + (present(dpnd_dlid ) .and. .not.present(dpnd_dlidn ))) then + call icepack_warnings_add(subname//' error in pond arguments') + call icepack_warnings_setabort(.true.,__FILE__,__LINE__) + return + endif + endif + if ((present(dsnow ) .and. .not.present(dsnown)) .or. & + (present(dsnown) .and. .not.present(dsnow ))) then call icepack_warnings_add(subname//' error in dsnow arguments') call icepack_warnings_setabort(.true.,__FILE__,__LINE__) return @@ -2526,6 +2661,17 @@ subroutine icepack_step_therm1(dt, & massicen(:,:) = c0 massliqn(:,:) = c0 + !----------------------------------------------------------------- + ! Initialize pond area fractions + !----------------------------------------------------------------- + do n= 1, ncat + if (tr_pond_lvl) then + apond(n) = apnd(n) * alvl(n) + else + apond(n) = apnd(n) + endif + enddo + !----------------------------------------------------------------- ! Initialize rate of snow loss to leads !----------------------------------------------------------------- @@ -2556,8 +2702,7 @@ subroutine icepack_step_therm1(dt, & !----------------------------------------------------------------- if (formdrag) then - call neutral_drag_coeffs (apnd , & - hpnd , ipnd , & + call neutral_drag_coeffs (apond , & alvl , vlvl , & aice , vice, & vsno , aicen , & @@ -2601,6 +2746,18 @@ subroutine icepack_step_therm1(dt, & meltbn (n) = c0 congeln(n) = c0 snoicen(n) = c0 + l_dpnd_flushn = c0 + l_dpnd_exponn = c0 + l_dpnd_freebdn = c0 + l_dpnd_initialn = c0 + l_dpnd_dlidn = c0 + if (tr_pond) then + if (present(dpnd_flushn) ) l_dpnd_flushn = dpnd_flushn(n) + if (present(dpnd_exponn) ) l_dpnd_exponn = dpnd_exponn(n) + if (present(dpnd_freebdn) ) l_dpnd_freebdn = dpnd_freebdn(n) + if (present(dpnd_initialn)) l_dpnd_initialn = dpnd_initialn(n) + if (present(dpnd_dlidn) ) l_dpnd_dlidn = dpnd_dlidn(n) + endif l_dsnown = c0 Trefn = c0 @@ -2686,8 +2843,8 @@ subroutine icepack_step_therm1(dt, & ! hadgem routine sets fluxes to default values in ice-only mode call set_sfcflux(aicen (n), & flatn_f (n), fsensn_f (n), & - fcondtopn_f(n), & fsurfn_f (n), & + fcondtopn_f(n), & flatn (n), fsensn (n), & fsurfn (n), & fcondtopn (n)) @@ -2700,11 +2857,20 @@ subroutine icepack_step_therm1(dt, & smliq(:) = smliqn(:,n) endif + if (semi_implicit_Tsfc) then + if (present(dfsurfdT)) dfsurfdTs_cpl = dfsurfdT(n) + if (present(dflatdT)) dflatdTs_cpl = dflatdT(n) + fsurf_cpl = fsurfn_f(n) + flat_cpl = flatn_f(n) + fsurf_cpl0 = fsurf_cpl + flat_cpl0 = flat_cpl + endif + call thermo_vertical(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), & + apond=apond (n), hpond=hpnd (n), & flw=flw, potT=potT, & Qa=Qa, rhoa=rhoa, & fsnow=fsnow, fpond=fpond, & @@ -2726,9 +2892,11 @@ subroutine icepack_step_therm1(dt, & smice=smice, massice=massicen (:,n), & smliq=smliq, massliq=massliqn (:,n), & congel=congeln (n), snoice=snoicen (n), & - mlt_onset=mlt_onset, frz_onset=frz_onset , & + mlt_onset=mlt_onset, frz_onset=frz_onset, & yday=yday, dsnow=l_dsnown , & - prescribed_ice=prescribed_ice) + prescribed_ice=prescribed_ice, & + dpnd_flush=l_dpnd_flushn, & + dpnd_expon=l_dpnd_exponn ) if (icepack_warnings_aborted(subname)) then write(warnstr,*) subname, ' ice: Vertical thermo error, cat ', n @@ -2736,6 +2904,17 @@ subroutine icepack_step_therm1(dt, & return endif + ! Translate changes in apond into apnd tracer + if (tr_pond_lvl) then + if (alvl(n) > puny) then + apnd(n) = max(apond(n) / alvl(n), c1) + else + apnd(n) = c0 + endif + else + apnd(n) = apond(n) + endif + if (snwgrain) then rsnwn (:,n) = rsnw (:) smicen(:,n) = smice(:) @@ -2830,7 +3009,35 @@ subroutine icepack_step_therm1(dt, & apnd=apnd (n), & hpnd=hpnd (n), & ipnd=ipnd (n), & - meltsliqn=l_meltsliqn(n)) + meltsliqn = l_meltsliqn(n), & + dpnd_freebdn = l_dpnd_freebdn, & + dpnd_initialn = l_dpnd_initialn,& + dpnd_dlidn = l_dpnd_dlidn, & + dpnd_flushn = l_dpnd_flushn) + if (icepack_warnings_aborted(subname)) return + + elseif (tr_pond_sealvl) then + call compute_ponds_sealvl(dt=dt, & + 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), & + apnd=apnd (n), & + hpnd=hpnd (n), & + ipnd=ipnd (n), & + meltsliqn = l_meltsliqn(n), & + dpnd_freebdn = l_dpnd_freebdn, & + dpnd_dlidn = l_dpnd_dlidn, & + dpnd_flushn = l_dpnd_flushn) if (icepack_warnings_aborted(subname)) return elseif (tr_pond_topo) then @@ -2876,6 +3083,14 @@ subroutine icepack_step_therm1(dt, & if (present(fswthrun_vdf)) l_fswthrun_vdf = fswthrun_vdf(n) if (present(fswthrun_idr)) l_fswthrun_idr = fswthrun_idr(n) if (present(fswthrun_idf)) l_fswthrun_idf = fswthrun_idf(n) + l_fswthrun_uvrdr = c0 + l_fswthrun_uvrdf = c0 + l_fswthrun_pardr = c0 + l_fswthrun_pardf = c0 + if (present(fswthrun_uvrdr)) l_fswthrun_uvrdr = fswthrun_uvrdr(n) + if (present(fswthrun_uvrdf)) l_fswthrun_uvrdf = fswthrun_uvrdf(n) + if (present(fswthrun_pardr)) l_fswthrun_pardr = fswthrun_pardr(n) + if (present(fswthrun_pardf)) l_fswthrun_pardf = fswthrun_pardf(n) call merge_fluxes (aicen=aicen_init(n), & flw=flw, & @@ -2895,6 +3110,10 @@ subroutine icepack_step_therm1(dt, & fswthrun_vdf=l_fswthrun_vdf, & fswthrun_idr=l_fswthrun_idr, & fswthrun_idf=l_fswthrun_idf, & + fswthrun_uvrdr=l_fswthrun_uvrdr, & + fswthrun_uvrdf=l_fswthrun_uvrdf, & + fswthrun_pardr=l_fswthrun_pardr, & + fswthrun_pardf=l_fswthrun_pardf, & strairxT=strairxT, strairyT=strairyT,& Cdn_atm_ratio=Cdn_atm_ratio, & fsurf=fsurf, fcondtop=fcondtop,& @@ -2911,6 +3130,10 @@ subroutine icepack_step_therm1(dt, & fswthru_vdf=fswthru_vdf, & fswthru_idr=fswthru_idr, & fswthru_idf=fswthru_idf, & + fswthru_uvrdr=fswthru_uvrdr, & + fswthru_uvrdf=fswthru_uvrdf, & + fswthru_pardr=fswthru_pardr, & + fswthru_pardf=fswthru_pardf, & melttn=melttn (n), meltsn=meltsn(n), & meltbn=meltbn (n), congeln=congeln(n),& meltt=meltt, melts=melts, & @@ -2925,13 +3148,28 @@ subroutine icepack_step_therm1(dt, & fiso_ocn=fiso_ocn, & fiso_ocnn=fiso_ocnn, & fiso_evap=fiso_evap, & - fiso_evapn=fiso_evapn) + fiso_evapn=fiso_evapn, & + dpnd_flush=dpnd_flush, & + dpnd_flushn=l_dpnd_flushn, & + dpnd_expon=dpnd_expon, & + dpnd_exponn=l_dpnd_exponn, & + dpnd_freebd=dpnd_freebd, & + dpnd_freebdn=l_dpnd_freebdn, & + dpnd_initial=dpnd_initial, & + dpnd_initialn=l_dpnd_initialn, & + dpnd_dlid=dpnd_dlid, & + dpnd_dlidn=l_dpnd_dlidn) if (icepack_warnings_aborted(subname)) return endif - if (present(dsnown )) dsnown(n) = l_dsnown + if (present(dsnown) ) dsnown (n) = l_dsnown + if (present(dpnd_flushn) ) dpnd_flushn (n) = l_dpnd_flushn + if (present(dpnd_exponn) ) dpnd_exponn (n) = l_dpnd_exponn + if (present(dpnd_freebdn) ) dpnd_freebdn (n) = l_dpnd_freebdn + if (present(dpnd_initialn)) dpnd_initialn(n) = l_dpnd_initialn + if (present(dpnd_dlidn) ) dpnd_dlidn (n) = l_dpnd_dlidn enddo ! ncat diff --git a/columnphysics/icepack_tracers.F90 b/columnphysics/icepack_tracers.F90 index fc3fafa8..c009450d 100644 --- a/columnphysics/icepack_tracers.F90 +++ b/columnphysics/icepack_tracers.F90 @@ -9,6 +9,7 @@ module icepack_tracers use icepack_kinds use icepack_parameters, only: c0, c1, puny, rhos, rsnw_fall, rhosnew use icepack_parameters, only: snwredist, snwgrain + use icepack_parameters, only: pndhyps, pndfrbd, pndhead, pndmacr use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -95,8 +96,7 @@ module icepack_tracers nt_bgc_DMS = 0, & ! nt_bgc_PON = 0, & ! zooplankton and detritus nt_bgc_hum = 0, & ! humic material - nt_zbgc_frac = 0, & ! fraction of tracer in the mobile phase - nt_bgc_S = 0 ! Bulk salinity in fraction ice with dynamic salinity (Bio grid) (deprecated) + nt_zbgc_frac = 0 ! fraction of tracer in the mobile phase logical (kind=log_kind), public :: & tr_iage = .false., & ! if .true., use age tracer @@ -105,6 +105,7 @@ module icepack_tracers tr_pond = .false., & ! if .true., use melt 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_pond_sealvl=.false., & ! if .true., use sealvl pond parameterization tr_snow = .false., & ! if .true., use snow redistribution or metamorphosis tracers tr_iso = .false., & ! if .true., use isotope tracers tr_aero = .false., & ! if .true., use aerosol tracers @@ -206,7 +207,7 @@ module icepack_tracers subroutine icepack_init_tracer_flags(& tr_iage_in, tr_FY_in, tr_lvl_in, tr_snow_in, & - tr_pond_in, tr_pond_lvl_in, tr_pond_topo_in, & + tr_pond_in, tr_pond_lvl_in, tr_pond_topo_in, tr_pond_sealvl_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, & tr_bgc_Am_in, tr_bgc_Sil_in, tr_bgc_DMS_in, tr_bgc_Fe_in, tr_bgc_hum_in, & @@ -219,6 +220,7 @@ subroutine icepack_init_tracer_flags(& tr_pond_in , & ! if .true., use melt 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_pond_sealvl_in,& ! if .true., use sealvl pond parameteriztion tr_snow_in , & ! if .true., use snow redistribution or metamorphosis tracers tr_fsd_in , & ! if .true., use floe size distribution tracers tr_iso_in , & ! if .true., use isotope tracers @@ -247,6 +249,7 @@ subroutine icepack_init_tracer_flags(& if (present(tr_pond_in)) tr_pond = tr_pond_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_pond_sealvl_in)) tr_pond_sealvl = tr_pond_sealvl_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 @@ -265,6 +268,29 @@ subroutine icepack_init_tracer_flags(& if (present(tr_bgc_hum_in)) tr_bgc_hum = tr_bgc_hum_in if (present(tr_bgc_PON_in)) tr_bgc_PON = tr_bgc_PON_in + ! tcraig, July, 2025 + ! This should not be here. These options should either + ! - be moved to namelist + ! - be removed and have all the features selected by tr_pond_* values + ! + ! Because we don't actually know what options work for the various + ! pond schemes (beyond the settings below), and we don't know which + ! options we want to be chooseable overall, we are leaving the declarations + ! in icepack_parameters and we are hardwiring them here so they will + ! be consistent with the tr_pond_sealvl settings as best as we know. + + if (tr_pond_sealvl) then + pndhyps = 'sealevel' + pndfrbd = 'category' + pndhead = 'hyps' + pndmacr = 'head' + else + pndhyps = 'sealevel' + pndfrbd = 'floor' + pndhead = 'perched' + pndmacr = 'lambda' + endif + end subroutine icepack_init_tracer_flags !======================================================================= @@ -273,7 +299,7 @@ end subroutine icepack_init_tracer_flags subroutine icepack_query_tracer_flags(& tr_iage_out, tr_FY_out, tr_lvl_out, tr_snow_out, & - tr_pond_out, tr_pond_lvl_out, tr_pond_topo_out, & + tr_pond_out, tr_pond_lvl_out, tr_pond_topo_out, tr_pond_sealvl_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, & tr_bgc_Am_out, tr_bgc_Sil_out, tr_bgc_DMS_out, tr_bgc_Fe_out, tr_bgc_hum_out, & @@ -286,6 +312,7 @@ subroutine icepack_query_tracer_flags(& tr_pond_out , & ! if .true., use melt 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_pond_sealvl_out,& ! if .true., use sealvl pond parameterization tr_snow_out , & ! if .true., use snow redistribution or metamorphosis tracers tr_fsd_out , & ! if .true., use floe size distribution tr_iso_out , & ! if .true., use isotope tracers @@ -314,6 +341,7 @@ subroutine icepack_query_tracer_flags(& if (present(tr_pond_out)) tr_pond_out = tr_pond 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_pond_sealvl_out)) tr_pond_sealvl_out = tr_pond_sealvl 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 @@ -353,6 +381,7 @@ subroutine icepack_write_tracer_flags(iounit) write(iounit,*) " tr_pond = ",tr_pond write(iounit,*) " tr_pond_lvl = ",tr_pond_lvl write(iounit,*) " tr_pond_topo = ",tr_pond_topo + write(iounit,*) " tr_pond_sealvl = ",tr_pond_sealvl write(iounit,*) " tr_snow = ",tr_snow write(iounit,*) " tr_fsd = ",tr_fsd write(iounit,*) " tr_iso = ",tr_iso @@ -391,7 +420,7 @@ subroutine icepack_init_tracer_indices(& nlt_bgc_DOC_in, nlt_bgc_DON_in, nlt_bgc_DIC_in, nlt_bgc_Fed_in, & nlt_bgc_Fep_in, nlt_bgc_Nit_in, nlt_bgc_Am_in, nlt_bgc_Sil_in, & nlt_bgc_DMSPp_in, nlt_bgc_DMSPd_in, nlt_bgc_DMS_in, nlt_bgc_hum_in, & - nlt_bgc_PON_in, nt_zbgc_frac_in, nt_bgc_S_in, nlt_chl_sw_in, & + nlt_bgc_PON_in, nt_zbgc_frac_in, nlt_chl_sw_in, & nlt_zaero_sw_in, & bio_index_o_in, bio_index_in) @@ -433,7 +462,6 @@ subroutine icepack_init_tracer_indices(& nlt_bgc_hum_in,& ! nlt_bgc_PON_in,& ! zooplankton and detritus nt_zbgc_frac_in,&! fraction of tracer in the mobile phase - nt_bgc_S_in, & ! (deprecated, was related to zsalinity) nlt_chl_sw_in ! points to total chla in trcrn_sw integer (kind=int_kind), dimension(:), intent(in), optional :: & @@ -515,7 +543,6 @@ subroutine icepack_init_tracer_indices(& if (present(nlt_bgc_PON_in) ) nlt_bgc_PON = nlt_bgc_PON_in if (present(nlt_chl_sw_in) ) nlt_chl_sw = nlt_chl_sw_in if (present(nt_zbgc_frac_in) ) nt_zbgc_frac = nt_zbgc_frac_in - if (present(nt_bgc_S_in) ) nt_bgc_S = nt_bgc_S_in if (present(bio_index_in)) then nsiz = size(bio_index_in) @@ -753,7 +780,7 @@ subroutine icepack_query_tracer_indices(& nlt_bgc_DOC_out, nlt_bgc_DON_out, nlt_bgc_DIC_out, nlt_bgc_Fed_out, & nlt_bgc_Fep_out, nlt_bgc_Nit_out, nlt_bgc_Am_out, nlt_bgc_Sil_out, & nlt_bgc_DMSPp_out, nlt_bgc_DMSPd_out, nlt_bgc_DMS_out, nlt_bgc_hum_out, & - nlt_bgc_PON_out, nt_zbgc_frac_out, nt_bgc_S_out, nlt_chl_sw_out, & + nlt_bgc_PON_out, nt_zbgc_frac_out, nlt_chl_sw_out, & nlt_zaero_sw_out, & bio_index_o_out, bio_index_out) @@ -795,7 +822,6 @@ subroutine icepack_query_tracer_indices(& nlt_bgc_hum_out,& ! nlt_bgc_PON_out,& ! zooplankton and detritus nt_zbgc_frac_out,&! fraction of tracer in the mobile phase - nt_bgc_S_out, & ! (deprecated, was related to zsalinity) nlt_chl_sw_out ! points to total chla in trcrn_sw integer (kind=int_kind), dimension(:), intent(out), optional :: & @@ -875,7 +901,6 @@ subroutine icepack_query_tracer_indices(& if (present(nlt_bgc_PON_out) ) nlt_bgc_PON_out = nlt_bgc_PON if (present(nlt_chl_sw_out) ) nlt_chl_sw_out = nlt_chl_sw if (present(nt_zbgc_frac_out) ) nt_zbgc_frac_out = nt_zbgc_frac - if (present(nt_bgc_S_out) ) nt_bgc_S_out = nt_bgc_S if (present(bio_index_o_out) ) bio_index_o_out = bio_index_o if (present(bio_index_out) ) bio_index_out = bio_index @@ -954,7 +979,6 @@ subroutine icepack_write_tracer_indices(iounit) write(iounit,*) " nlt_bgc_PON = ",nlt_bgc_PON write(iounit,*) " nlt_chl_sw = ",nlt_chl_sw write(iounit,*) " nt_zbgc_frac = ",nt_zbgc_frac - write(iounit,*) " nt_bgc_S = ",nt_bgc_S," (deprecated)" write(iounit,*) " max_nbtrcr = ",max_nbtrcr do k = 1, max_nbtrcr @@ -1203,7 +1227,7 @@ subroutine icepack_compute_tracers (trcr_depend, & trcr_base, n_trcr_strata, & nt_strata, trcrn, Tf) - integer (kind=int_kind), dimension (ntrcr), intent(in) :: & + integer (kind=int_kind), dimension (:), intent(in) :: & trcr_depend, & ! = 0 for aicen tracers, 1 for vicen, 2 for vsnon n_trcr_strata ! number of underlying tracer layers @@ -1222,7 +1246,7 @@ subroutine icepack_compute_tracers (trcr_depend, & vicen , & ! volume per unit area of ice (m) vsnon ! volume per unit area of snow (m) - real (kind=dbl_kind), dimension (ntrcr), intent(out) :: & + real (kind=dbl_kind), dimension (:), intent(out) :: & trcrn ! ice tracers real (kind=dbl_kind), intent(in) :: & diff --git a/columnphysics/icepack_wavefracspec.F90 b/columnphysics/icepack_wavefracspec.F90 index e3ba8a78..96d070c0 100644 --- a/columnphysics/icepack_wavefracspec.F90 +++ b/columnphysics/icepack_wavefracspec.F90 @@ -31,6 +31,7 @@ module icepack_wavefracspec use icepack_kinds use icepack_parameters, only: p01, p5, c0, c1, c2, c3, c4, c10 use icepack_parameters, only: bignum, puny, gravit, pi + use icepack_parameters, only: wave_spec_type, wave_height_type use icepack_tracers, only: nt_fsd, ncat, nfsd use icepack_warnings, only: warnstr, icepack_warnings_add use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted @@ -180,18 +181,12 @@ end function get_dafsd_wave ! ! authors: 2018 Lettie Roach, NIWA/VUW ! - subroutine icepack_step_wavefracture(wave_spec_type, & - wave_height_type, & + subroutine icepack_step_wavefracture( & dt, nfreq, & aice, vice, aicen, & wave_spectrum, wavefreq, dwavefreq, & - trcrn, d_afsd_wave, wave_height) + trcrn, d_afsd_wave, wave_height) - - character (len=char_len), intent(in) :: & - wave_spec_type, & ! type of wave spectrum forcing - wave_height_type ! type of wave height forcing - integer (kind=int_kind), intent(in) :: & nfreq ! number of wave frequency categories @@ -218,7 +213,7 @@ subroutine icepack_step_wavefracture(wave_spec_type, & d_afsd_wave ! change in fsd due to waves real (kind=dbl_kind), intent(in), optional :: & - wave_height ! ! significant wave height (m) + wave_height ! significant wave height (m) real (kind=dbl_kind), dimension(nfsd,ncat) :: & d_afsdn_wave ! change in fsd due to waves, per category @@ -260,19 +255,15 @@ subroutine icepack_step_wavefracture(wave_spec_type, & ! if all ice is not in first floe size category if (.NOT. ALL(trcrn(nt_fsd,:).ge.c1-puny)) then - ! Add option to use wave height from wave model or file - if (trim(wave_height_type) == 'internal') then - local_sig_ht = c4*SQRT(SUM(wave_spectrum(:)*dwavefreq(:))) - elseif (trim(wave_height_type) == 'coupled') then + ! set significant wave height if (present(wave_height)) then local_sig_ht = wave_height - else + elseif (trim(wave_height_type) == 'coupled') then call icepack_warnings_add(subname//& - ' wave_height_type=coupled, but NO wave height data found') + ' ERROR: wave_height_type=coupled but no wave height data found') call icepack_warnings_setabort(.true.,__FILE__,__LINE__) endif - endif - + ! do not try to fracture for minimal ice concentration or zero wave spectrum ! if ((aice > p01).and.(MAXVAL(wave_spectrum(:)) > puny)) then if ((aice > p01).and.(local_sig_ht>0.1_dbl_kind)) then @@ -280,7 +271,7 @@ subroutine icepack_step_wavefracture(wave_spec_type, & hbar = vice / aice ! calculate fracture histogram - call wave_frac(nfreq, wave_spec_type, & + call wave_frac(nfreq, & wavefreq, dwavefreq, & hbar, wave_spectrum, fracture_hist) @@ -408,16 +399,13 @@ end subroutine icepack_step_wavefracture ! ! authors: 2018 Lettie Roach, NIWA/VUW - subroutine wave_frac(nfreq, wave_spec_type, & + subroutine wave_frac(nfreq, & wavefreq, dwavefreq, & hbar, spec_efreq, frac_local) integer (kind=int_kind), intent(in) :: & nfreq ! number of wave frequency categories - character (len=char_len), intent(in) :: & - wave_spec_type ! type of wave spectrum forcing - real (kind=dbl_kind), intent(in) :: & hbar ! mean ice thickness (m) diff --git a/columnphysics/icepack_zbgc.F90 b/columnphysics/icepack_zbgc.F90 index 1cb7a6c3..7ee66276 100644 --- a/columnphysics/icepack_zbgc.F90 +++ b/columnphysics/icepack_zbgc.F90 @@ -12,7 +12,7 @@ module icepack_zbgc use icepack_parameters !use icepack_parameters, only: c0, c1, c2, p001, p1, p5, puny - !use icepack_parameters, only: depressT, rhosi, min_salin, salt_loss + !use icepack_parameters, only: depressT, rhosi, min_salin !use icepack_parameters, only: fr_resp, algal_vel, R_dFe2dust, dustFe_sol, T_max !use icepack_parameters, only: op_dep_min, fr_graze_s, fr_graze_e, fr_mort2min, fr_dFe !use icepack_parameters, only: k_nitrif, t_iron_conv, max_loss, max_dfe_doc1 diff --git a/columnphysics/icepack_zbgc_shared.F90 b/columnphysics/icepack_zbgc_shared.F90 index 08c6753d..b7d3ec6e 100644 --- a/columnphysics/icepack_zbgc_shared.F90 +++ b/columnphysics/icepack_zbgc_shared.F90 @@ -588,8 +588,7 @@ subroutine merge_bgc_fluxes (dt, & bio_index, & aicen, & vicen, vsnon, & - iphin, & - trcrn, aice_init, & + iphin, trcrn, & flux_bion, flux_bio, & upNOn, upNHn, & upNO, upNH, & @@ -618,8 +617,7 @@ subroutine merge_bgc_fluxes (dt, & real (kind=dbl_kind), intent(in):: & aicen , & ! concentration of ice vicen , & ! volume of ice (m) - vsnon , & ! volume of snow(m) - aice_init ! initial concentration of ice + vsnon ! volume of snow(m) ! single category rates real (kind=dbl_kind), dimension(:), intent(in):: & diff --git a/columnphysics/version.txt b/columnphysics/version.txt index f46731dc..416c7139 100644 --- a/columnphysics/version.txt +++ b/columnphysics/version.txt @@ -1 +1 @@ -ICEPACK 1.5.0 +ICEPACK 1.5.3 diff --git a/configuration/driver/icedrv_InitMod.F90 b/configuration/driver/icedrv_InitMod.F90 index ba1b1de6..0785ab7c 100644 --- a/configuration/driver/icedrv_InitMod.F90 +++ b/configuration/driver/icedrv_InitMod.F90 @@ -42,7 +42,7 @@ subroutine icedrv_initialize ! use icedrv_diagnostics, only: icedrv_diagnostics_debug use icedrv_flux, only: init_coupler_flux, init_history_therm, & init_flux_atm_ocn - use icedrv_forcing, only: init_forcing, get_forcing, get_wave_spec + use icedrv_forcing, only: init_forcing, get_forcing, get_wave_spec, precalc_forc use icedrv_forcing_bgc, only: get_forcing_bgc, faero_default, fiso_default, init_forcing_bgc use icedrv_restart_shared, only: restart use icedrv_init, only: input_data, init_state, init_grid2, init_fsd @@ -56,6 +56,7 @@ subroutine icedrv_initialize tr_aero, & ! from icepack tr_iso, & ! from icepack tr_zaero, & ! from icepack + tr_pond_sealvl, & ! from icepack tr_fsd, wave_spec character(len=*), parameter :: subname='(icedrv_initialize)' @@ -110,6 +111,12 @@ subroutine icedrv_initialize call init_restart ! initialize restart variables call init_history_therm ! initialize thermo history variables + call icepack_query_tracer_flags(tr_pond_sealvl_out=tr_pond_sealvl) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted(subname)) then + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif + if (restart) & call init_shortwave ! initialize radiative transfer @@ -137,7 +144,11 @@ subroutine icedrv_initialize call init_forcing ! initialize forcing (standalone) if (skl_bgc .or. z_tracers) call init_forcing_bgc !cn if (tr_fsd .and. wave_spec) call get_wave_spec ! wave spectrum in ice - call get_forcing(istep1) ! get forcing from data arrays + if (precalc_forc) then + call get_forcing(istep) ! precalculated arrays are indexed by istep + else + call get_forcing(istep1) ! get forcing from data arrays + endif if (tr_snow) then call icepack_init_snow ! snow aging table diff --git a/configuration/driver/icedrv_MAIN.F90 b/configuration/driver/icedrv_MAIN.F90 index c8564d4e..becd6386 100644 --- a/configuration/driver/icedrv_MAIN.F90 +++ b/configuration/driver/icedrv_MAIN.F90 @@ -1,17 +1,17 @@ !======================================================================= -! Copyright (c) 2024, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! -! Copyright 2024. Triad National Security, LLC. This software was -! produced under U.S. Government contract DE-AC52-06NA25396 for Los -! Alamos National Laboratory (LANL), which is operated by Triad -! National Security, LLC for the U.S. Department of Energy. The U.S. -! Government has rights to use, reproduce, and distribute this software. -! NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC MAKES ANY -! WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF -! THIS SOFTWARE. If software is modified to produce derivative works, -! such modified software should be clearly marked, so as not to confuse -! it with the version available from LANL. +! This program was produced under U.S. Government contract 89233218CNA000001 +! for Los Alamos National Laboratory (LANL), which is operated by Triad +! National Security, LLC for the U.S. Department of Energy/National Nuclear +! Security Administration. All rights in the program are reserved by Triad +! National Security, LLC, and the U.S. Department of Energy/National Nuclear +! Security Administration. The Government is granted for itself and others +! acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +! license in this material to reproduce, prepare. derivative works, +! distribute copies to the public, perform publicly and display publicly, +! and to permit others to do so. ! ! The full license and distribution policy are available from ! https://github.com/CICE-Consortium diff --git a/configuration/driver/icedrv_RunMod.F90 b/configuration/driver/icedrv_RunMod.F90 index a7bc82bd..fb784cc5 100644 --- a/configuration/driver/icedrv_RunMod.F90 +++ b/configuration/driver/icedrv_RunMod.F90 @@ -32,7 +32,7 @@ module icedrv_RunMod subroutine icedrv_run use icedrv_calendar, only: istep, istep1, time, dt, stop_now, calendar - use icedrv_forcing, only: get_forcing, get_wave_spec + use icedrv_forcing, only: get_forcing, get_wave_spec, precalc_forc use icedrv_forcing_bgc, only: faero_default, fiso_default, get_forcing_bgc use icedrv_flux, only: init_flux_atm_ocn use icedrv_history, only: history_format, history_close @@ -74,7 +74,11 @@ subroutine icedrv_run file=__FILE__,line= __LINE__) if (tr_fsd .and. wave_spec) call get_wave_spec ! wave spectrum in ice - call get_forcing(istep1) ! get forcing from data arrays + if (precalc_forc) then + call get_forcing(istep) ! precalculated arrays are indexed by istep + else + call get_forcing(istep1) ! get forcing from data arrays + endif ! biogeochemistry forcing if (tr_iso) call fiso_default ! default values diff --git a/configuration/driver/icedrv_calendar.F90 b/configuration/driver/icedrv_calendar.F90 index d2cab40a..e5e02678 100644 --- a/configuration/driver/icedrv_calendar.F90 +++ b/configuration/driver/icedrv_calendar.F90 @@ -93,10 +93,6 @@ module icedrv_calendar character (len=1), public :: & dumpfreq ! restart frequency, 'y','m','d' - character (len=char_len), public :: & - calendar_type ! differentiates Gregorian from other calendars - ! default = ' ' - !======================================================================= contains @@ -144,9 +140,6 @@ subroutine init_calendar ' because use_leap_years = .true.' end if - calendar_type = ' ' - if (use_leap_years .and. days_per_year == 365) calendar_type = 'Gregorian' - dayyr = real(days_per_year, kind=dbl_kind) if (days_per_year == 360) then daymo = daymo360 diff --git a/configuration/driver/icedrv_flux.F90 b/configuration/driver/icedrv_flux.F90 index 321a8491..b0509286 100644 --- a/configuration/driver/icedrv_flux.F90 +++ b/configuration/driver/icedrv_flux.F90 @@ -129,6 +129,9 @@ module icedrv_flux qdp , & ! deep ocean heat flux (W/m^2), negative upward hmix ! mixed layer depth (m) + real (kind=dbl_kind), public :: & + sst_init ! initial sea surface temperature (C) + ! water isotopes real (kind=dbl_kind), dimension (nx), public :: & HDO_ocn , & ! seawater concentration of HDO (kg/kg) @@ -184,6 +187,12 @@ module icedrv_flux fswthru_idr , & ! nir dir shortwave penetrating to ocean (W/m^2) fswthru_idf ! nir dif shortwave penetrating to ocean (W/m^2) + ! fixed ocean mixed layer properties (are overwritten by forcing data) + real (kind=dbl_kind), public :: & + sss_fixed , & ! Sea surface salinity (PSU) + qdp_fixed , & ! Deep ocean heat flux (negative upward, W/m^2) + hmix_fixed ! Mixed layer depth (m) + ! internal real (kind=dbl_kind), & @@ -255,6 +264,25 @@ module icedrv_flux fsensn, & ! category sensible heat flux flatn ! category latent heat flux + ! General pond diagnostic variables + real (kind=dbl_kind), & + dimension (nx,ncat), public :: & + ! Like melttn these are defined as volume per unit category area + dpnd_flushn, & ! category pond flushing rate due to ice permeability + dpnd_exponn, & ! category exponential pond drainage rate + dpnd_freebdn, & ! category pond drainage rate due to freeboard constraint + dpnd_initialn, & ! category runoff rate due to rfrac (m/step) + dpnd_dlidn ! category pond loss/gain due to ice lid (m/step) + + real (kind=dbl_kind), dimension (nx), public :: & + dpnd_flush, & ! pond flushing rate due to ice permeability (m/step) + dpnd_expon, & ! exponential pond drainage rate (m/step) + dpnd_freebd, & ! pond drainage rate due to freeboard constraint (m/step) + dpnd_initial, & ! runoff rate due to rfrac (m/step) + dpnd_dlid, & ! pond loss/gain (+/-) to ice lid freezing/melting (m/step) + dpnd_melt, & ! pond 'drainage' due to ice melting (m / step) + dpnd_ridge ! pond drainage due to ridging (m / step) + ! As above but these remain grid box mean values i.e. they are not ! divided by aice at end of ice_dynamics. ! These are used for generating @@ -485,8 +513,8 @@ subroutine init_coupler_flux uocn (:) = c0 ! surface ocean currents (m/s) vocn (:) = c0 frzmlt (:) = c0 ! freezing/melting potential (W/m^2) - sss (:) = 34.0_dbl_kind ! sea surface salinity (ppt) - sst (:) = -1.8_dbl_kind ! sea surface temperature (C) + sss (:) = sss_fixed ! sea surface salinity (ppt) + sst (:) = sst_init ! sea surface temperature (C) sstdat (:) = sst(:) ! sea surface temperature (C) ! water isotopes from ocean @@ -501,8 +529,8 @@ subroutine init_coupler_flux if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__,line= __LINE__) - qdp (:) = c0 ! deep ocean heat flux (W/m^2) - hmix (:) = c20 ! ocean mixed layer depth + qdp (:) = qdp_fixed ! deep ocean heat flux (W/m^2) + hmix (:) = hmix_fixed ! ocean mixed layer depth !----------------------------------------------------------------- ! fluxes sent to atmosphere @@ -660,6 +688,7 @@ subroutine init_history_therm congel (:) = c0 frazil (:) = c0 snoice (:) = c0 + Tsnice (:) = c0 dsnow (:) = c0 meltt (:) = c0 melts (:) = c0 @@ -688,6 +717,13 @@ subroutine init_history_therm apeff_ai (:) = c0 snowfrac (:) = c0 frazil_diag (:) = c0 + dpnd_flush (:) = c0 + dpnd_expon (:) = c0 + dpnd_freebd (:) = c0 + dpnd_initial(:) = c0 + dpnd_dlid (:) = c0 + dpnd_melt (:) = c0 + dpnd_ridge (:) = c0 ! drag coefficients are computed prior to the atmo_boundary call, ! during the thermodynamics section diff --git a/configuration/driver/icedrv_forcing.F90 b/configuration/driver/icedrv_forcing.F90 index 98e390e2..2d773069 100644 --- a/configuration/driver/icedrv_forcing.F90 +++ b/configuration/driver/icedrv_forcing.F90 @@ -10,6 +10,7 @@ module icedrv_forcing use icedrv_domain_size, only: nx use icedrv_calendar, only: time, nyr, dayyr, mday, month, secday use icedrv_calendar, only: daymo, daycal, dt, yday, sec + use icedrv_calendar, only: npt, use_leap_years, time0, year_init use icedrv_constants, only: nu_diag, nu_forcing, nu_open_clos use icedrv_constants, only: c0, c1, c2, c10, c100, p5, c4, c24 use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted @@ -20,14 +21,18 @@ module icedrv_forcing use icedrv_flux, only: zlvl, Tair, potT, rhoa, uatm, vatm, wind, & strax, stray, fsw, swvdr, swvdf, swidr, swidf, Qa, flw, frain, & fsnow, sst, sss, uocn, vocn, qdp, hmix, Tf, opening, closing, sstdat +#ifdef USE_NETCDF + use netcdf +#endif implicit none private + public :: init_forcing, get_forcing, interp_coeff, & interp_coeff_monthly, get_wave_spec - integer (kind=int_kind), parameter :: & - ntime = 8760 ! number of data points in time + integer (kind=int_kind) :: & + ntime ! number of data points in time integer (kind=int_kind), public :: & ycycle , & ! number of years in forcing cycle @@ -35,47 +40,45 @@ module icedrv_forcing fyear , & ! current year in forcing cycle fyear_final ! last year in cycle - real (kind=dbl_kind), dimension(ntime) :: & - fsw_data, & ! field values at temporal data points - cldf_data, & - fsnow_data, & - Tair_data, & - uatm_data, & - vatm_data, & - wind_data, & - strax_data, & - stray_data, & - rhum_data, & - Qa_data, & - rhoa_data, & - potT_data, & - flw_data, & - qdp_data, & - sst_data, & - sss_data, & - uocn_data, & - vocn_data, & - frain_data, & - swvdr_data, & - swvdf_data, & - swidr_data, & - swidf_data, & - zlvl_data, & - hmix_data + real (kind=dbl_kind), allocatable :: & + fsw_data(:), & ! field values at temporal data points + cldf_data(:), & + fsnow_data(:), & + Tair_data(:), & + uatm_data(:), & + vatm_data(:), & + wind_data(:), & + strax_data(:), & + stray_data(:), & + rhum_data(:), & + Qa_data(:), & + rhoa_data(:), & + potT_data(:), & + flw_data(:), & + qdp_data(:), & + sst_data(:), & + sss_data(:), & + uocn_data(:), & + vocn_data(:), & + frain_data(:), & + swvdr_data(:), & + swvdf_data(:), & + swidr_data(:), & + swidf_data(:), & + zlvl_data(:), & + hmix_data(:), & + open_data(:), & + clos_data(:) real (kind=dbl_kind), dimension(nx) :: & sst_temp - real (kind=dbl_kind), dimension(ntime) :: & - open_data, & - clos_data - character(char_len), public :: & atm_data_format, & ! 'bin'=binary or 'nc'=netcdf ocn_data_format, & ! 'bin'=binary or 'nc'=netcdf bgc_data_format, & ! 'bin'=binary or 'nc'=netcdf - atm_data_type, & ! 'default', 'clim', 'CFS' - ocn_data_type, & ! 'default', 'SHEBA' + atm_data_type, & ! 'default', 'clim', 'CFS', 'MDF' + ocn_data_type, & ! 'default', 'SHEBA' 'MDF' bgc_data_type, & ! 'default', 'ISPOL', 'NICE' lateral_flux_type, & ! 'uniform_ice', 'open_water' atm_data_file, & ! atmospheric forcing data file @@ -94,8 +97,9 @@ module icedrv_forcing frcidf = 0.17_dbl_kind ! frac of incoming sw in near IR diffuse band logical (kind=log_kind), public :: & - oceanmixed_ice , & ! if true, use internal ocean mixed layer - restore_ocn ! restore sst if true + oceanmixed_ice , & ! if true, use internal ocean mixed layer + restore_ocn , & ! restore sst if true + precalc_forc ! whether to precalculate forcing real (kind=dbl_kind), public :: & trest, & ! restoring time scale (sec) @@ -120,6 +124,32 @@ subroutine init_forcing character(len=*), parameter :: subname='(init_forcing)' + ! Initialize ntime and allocate data arrays + if (precalc_forc) then + if (trim(atm_data_type(1:3)) /= 'MDF') & + call icedrv_system_abort(string=subname//& + 'precalc_forc should only be used with MDF atmosphere', & + file=__FILE__,line=__LINE__) + if (.not. ((trim(ocn_data_type(1:3)) == 'MDF') & + .or. (trim(ocn_data_type(1:7)) == 'default'))) & + call icedrv_system_abort(string=subname//& + 'precalc_forc should only be used with MDF ocean or'//& + ' default ocean', file=__FILE__,line=__LINE__) + ntime = npt + else + ntime = 8760 + endif + allocate(fsw_data(ntime), cldf_data(ntime), fsnow_data(ntime), & + Tair_data(ntime), uatm_data(ntime), vatm_data(ntime), & + wind_data(ntime), strax_data(ntime), stray_data(ntime), & + rhum_data(ntime), Qa_data(ntime), rhoa_data(ntime), & + potT_data(ntime), flw_data(ntime), qdp_data(ntime), & + sst_data(ntime), sss_data(ntime), uocn_data(ntime), & + vocn_data(ntime), frain_data(ntime), swvdr_data(ntime), & + swvdf_data(ntime), swidr_data(ntime), swidf_data(ntime), & + zlvl_data(ntime), hmix_data(ntime), open_data(ntime), & + clos_data(ntime)) + fyear = fyear_init + mod(nyr-1,ycycle) ! current year fyear_final = fyear_init + ycycle - 1 ! last year in forcing cycle @@ -153,6 +183,7 @@ subroutine init_forcing fsnow_data(:) = fsnow(i) ! snowfall rate (kg/m^2 s) qdp_data(:) = qdp (i) ! deep ocean heat flux (W/m^2) sss_data(:) = sss (i) ! sea surface salinity + hmix_data(:)= hmix (i) ! ocean mixed layer depth (m) uocn_data(:) = uocn (i) ! ocean current components (m/s) vocn_data(:) = vocn (i) cldf_data(:) = c0 ! cloud fraction @@ -161,6 +192,7 @@ subroutine init_forcing if (trim(atm_data_type(1:4)) == 'clim') call atm_climatological if (trim(atm_data_type(1:5)) == 'ISPOL') call atm_ISPOL if (trim(atm_data_type(1:4)) == 'NICE') call atm_NICE + if (trim(atm_data_type(1:3)) == 'MDF') call atm_MDF if (trim(ocn_data_type(1:5)) == 'SHEBA') call ice_open_clos if (restore_ocn) then @@ -176,6 +208,7 @@ subroutine init_forcing if (trim(ocn_data_type(1:5)) == 'ISPOL') call ocn_ISPOL if (trim(ocn_data_type(1:4)) == 'NICE') call ocn_NICE + if (trim(ocn_data_type(1:3)) == 'MDF') call ocn_MDF call prepare_forcing (Tair_data, fsw_data, & cldf_data, & @@ -227,164 +260,194 @@ subroutine get_forcing(timestep) character(len=*), parameter :: subname='(get_forcing)' - if (trim(atm_data_type) == 'CFS') then - ! calculate data index corresponding to current timestep - i = mod(timestep-1,ntime)+1 ! repeat forcing cycle - mlast = i - mnext = mlast - c1intp = c1 - c2intp = c0 - - ! fill all grid boxes with the same forcing data - Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) - Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) - uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) - vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) - fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) - flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) - fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) + if (precalc_forc) then + ! Fill all grid boxes with same forcing data + Tair (:) = Tair_data(timestep) + Qa (:) = Qa_data(timestep) + uatm (:) = uatm_data(timestep) + vatm (:) = vatm_data(timestep) + fsnow(:) = fsnow_data(timestep) + flw (:) = flw_data(timestep) + fsw (:) = fsw_data(timestep) ! derived (or not otherwise set) - potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) - wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) - strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) - stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) - rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) - frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) - swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) - swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) - swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) - swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) - - elseif (trim(atm_data_type) == 'clim') then - midmonth = 15 ! assume data is given on 15th of every month - recslot = 1 ! latter half of month - if (mday < midmonth) recslot = 2 ! first half of month - if (recslot == 1) then - mlast = month - mnext = mod(month ,12) + 1 - else ! recslot = 2 - mlast = mod(month+10,12) + 1 - mnext = month - endif - call interp_coeff_monthly(recslot, c1intp, c2intp) + potT (:) = potT_data(timestep) + wind (:) = wind_data(timestep) + strax(:) = strax_data(timestep) + stray(:) = stray_data(timestep) + rhoa (:) = rhoa_data(timestep) + frain(:) = frain_data(timestep) + swvdr(:) = swvdr_data(timestep) + swvdf(:) = swvdf_data(timestep) + swidr(:) = swidr_data(timestep) + swidf(:) = swidf_data(timestep) + + ! Ocean forcing + sst_temp(:) = sst_data(timestep) + sss (:) = sss_data(timestep) + uocn (:) = uocn_data(timestep) + vocn (:) = vocn_data(timestep) + qdp (:) = qdp_data(timestep) + + else + if (trim(atm_data_type) == 'CFS') then + ! calculate data index corresponding to current timestep + i = mod(timestep-1,ntime)+1 ! repeat forcing cycle + mlast = i + mnext = mlast + c1intp = c1 + c2intp = c0 + + ! fill all grid boxes with the same forcing data + Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) + Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) + uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) + vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) + fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) + flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) + fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) + + ! derived (or not otherwise set) + potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) + wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) + strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) + stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) + rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) + frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) + swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) + swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) + swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) + swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) + + elseif (trim(atm_data_type) == 'clim') then + midmonth = 15 ! assume data is given on 15th of every month + recslot = 1 ! latter half of month + if (mday < midmonth) recslot = 2 ! first half of month + if (recslot == 1) then + mlast = month + mnext = mod(month ,12) + 1 + else ! recslot = 2 + mlast = mod(month+10,12) + 1 + mnext = month + endif + call interp_coeff_monthly(recslot, c1intp, c2intp) + + ! fill all grid boxes with the same forcing data + Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) + Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) + uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) + vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) + fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) + flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) + fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) + + ! derived (or not otherwise set) + potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) + wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) + strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) + stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) + rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) + frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) + swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) + swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) + swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) + swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) + + elseif (trim(atm_data_type) == 'ISPOL') then + + offndy = 0 ! first data record (Julian day) + offset = real(offndy,dbl_kind)*secday + dataloc = 1 ! data located at middle of interval + maxrec = 365 + recslot = 2 + recnum = mod(int(yday)+maxrec-offndy-1,maxrec)+1 + mlast = mod(recnum+maxrec-2,maxrec) + 1 + mnext = mod(recnum-1, maxrec) + 1 + call interp_coeff (recnum, recslot, secday, dataloc, & + c1intp, c2intp, offset) - ! fill all grid boxes with the same forcing data Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) - flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) - fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) - - ! derived (or not otherwise set) - potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) - wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) - strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) - stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) - rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) - frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) - swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) - swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) - swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) - swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) - - elseif (trim(atm_data_type) == 'ISPOL') then - - offndy = 0 ! first data record (Julian day) - offset = real(offndy,dbl_kind)*secday - dataloc = 1 ! data located at middle of interval - maxrec = 365 - recslot = 2 - recnum = mod(int(yday)+maxrec-offndy-1,maxrec)+1 - mlast = mod(recnum+maxrec-2,maxrec) + 1 - mnext = mod(recnum-1, maxrec) + 1 - call interp_coeff (recnum, recslot, secday, dataloc, & - c1intp, c2intp, offset) - - Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) - Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) - uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) - vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) - fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) - ! derived (or not otherwise set) - potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) - wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) - strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) - stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) - rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) - frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) - - sec6hr = secday/c4; ! seconds in 6 hours - offndy = 0 - maxrec = 1460 - recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr) - recnum = mod(recnum+maxrec-4*offndy-1,maxrec)+1 ! data begins on 16 June 2004 - recslot = 2 - mlast = mod(recnum+maxrec-2,maxrec) + 1 - mnext = mod(recnum-1, maxrec) + 1 - call interp_coeff (recnum, recslot, sec6hr, dataloc, & - c1intp, c2intp, offset) + ! derived (or not otherwise set) + potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) + wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) + strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) + stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) + rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) + frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) + + sec6hr = secday/c4; ! seconds in 6 hours + offndy = 0 + maxrec = 1460 + recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr) + recnum = mod(recnum+maxrec-4*offndy-1,maxrec)+1 ! data begins on 16 June 2004 + recslot = 2 + mlast = mod(recnum+maxrec-2,maxrec) + 1 + mnext = mod(recnum-1, maxrec) + 1 + call interp_coeff (recnum, recslot, sec6hr, dataloc, & + c1intp, c2intp, offset) - fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) - flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) + fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) + flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) - ! derived - swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) - swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) - swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) - swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) + ! derived + swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) + swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) + swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) + swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) - elseif (trim(atm_data_type) == 'NICE') then + elseif (trim(atm_data_type) == 'NICE') then - offndy = 0 ! first data record (Julian day) - offset = real(offndy,dbl_kind)*secday - dataloc = 1 ! data located in middle of interval - maxrec = 365 - recslot = 2 - recnum = mod(int(yday)+maxrec-offndy-1,maxrec)+1 - mlast = mod(recnum+maxrec-2,maxrec) + 1 - mnext = mod(recnum-1, maxrec) + 1 - call interp_coeff (recnum, recslot, secday, dataloc, & - c1intp, c2intp, offset) + offndy = 0 ! first data record (Julian day) + offset = real(offndy,dbl_kind)*secday + dataloc = 1 ! data located in middle of interval + maxrec = 365 + recslot = 2 + recnum = mod(int(yday)+maxrec-offndy-1,maxrec)+1 + mlast = mod(recnum+maxrec-2,maxrec) + 1 + mnext = mod(recnum-1, maxrec) + 1 + call interp_coeff (recnum, recslot, secday, dataloc, & + c1intp, c2intp, offset) - Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) - Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) - uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) - vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) - fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) + Tair (:) = c1intp * Tair_data(mlast) + c2intp * Tair_data(mnext) + Qa (:) = c1intp * Qa_data(mlast) + c2intp * Qa_data(mnext) + uatm (:) = c1intp * uatm_data(mlast) + c2intp * uatm_data(mnext) + vatm (:) = c1intp * vatm_data(mlast) + c2intp * vatm_data(mnext) + fsnow(:) = c1intp * fsnow_data(mlast) + c2intp * fsnow_data(mnext) - ! derived (or not otherwise set) - potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) - wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) - strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) - stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) - rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) - frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) - - sec6hr = secday/c4; ! seconds in 6 hours - maxrec = 1460 - dataloc = 2 ! data located at end of interval - recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr) - recnum = mod(recnum+maxrec-4*offndy-1,maxrec)+1 - recslot = 2 - mlast = mod(recnum+maxrec-2,maxrec) + 1 - mnext = mod(recnum-1, maxrec) + 1 - call interp_coeff (recnum, recslot, sec6hr, dataloc, & - c1intp, c2intp, offset) + ! derived (or not otherwise set) + potT (:) = c1intp * potT_data(mlast) + c2intp * potT_data(mnext) + wind (:) = c1intp * wind_data(mlast) + c2intp * wind_data(mnext) + strax(:) = c1intp * strax_data(mlast) + c2intp * strax_data(mnext) + stray(:) = c1intp * stray_data(mlast) + c2intp * stray_data(mnext) + rhoa (:) = c1intp * rhoa_data(mlast) + c2intp * rhoa_data(mnext) + frain(:) = c1intp * frain_data(mlast) + c2intp * frain_data(mnext) + + sec6hr = secday/c4; ! seconds in 6 hours + maxrec = 1460 + dataloc = 2 ! data located at end of interval + recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr) + recnum = mod(recnum+maxrec-4*offndy-1,maxrec)+1 + recslot = 2 + mlast = mod(recnum+maxrec-2,maxrec) + 1 + mnext = mod(recnum-1, maxrec) + 1 + call interp_coeff (recnum, recslot, sec6hr, dataloc, & + c1intp, c2intp, offset) - fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) - flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) + fsw (:) = c1intp * fsw_data(mlast) + c2intp * fsw_data(mnext) + flw (:) = c1intp * flw_data(mlast) + c2intp * flw_data(mnext) - ! derived - swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) - swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) - swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) - swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) + ! derived + swvdr(:) = c1intp * swvdr_data(mlast) + c2intp * swvdr_data(mnext) + swvdf(:) = c1intp * swvdf_data(mlast) + c2intp * swvdf_data(mnext) + swidr(:) = c1intp * swidr_data(mlast) + c2intp * swidr_data(mnext) + swidf(:) = c1intp * swidf_data(mlast) + c2intp * swidf_data(mnext) - endif + endif ! possible bug: is the ocean data also offset to the beginning of the field campaigns? @@ -441,6 +504,7 @@ subroutine get_forcing(timestep) qdp (:) = c1intp * qdp_data(mlast) + c2intp * qdp_data(mnext) endif + endif call finish_ocn_forcing(sst_temp) @@ -534,6 +598,10 @@ subroutine atm_climatological ! 6 W/m2 warming of mixed layer from deep ocean qdp_data(:) = -6.0 ! 2 W/m2 from deep + 4 W/m2 counteracting larger ! SH+LH with bulk transfer than in MU 71 + ! Warn that this overwrites default and namelist value + write(nu_diag,*) subname + write(nu_diag,*) 'WARNING: atm_data_type = clim overwrites '//& + 'oceanic heat flux convergence from default or namelist' end subroutine atm_climatological @@ -972,6 +1040,406 @@ subroutine atm_NICE end subroutine atm_NICE +!======================================================================= + + subroutine atm_MDF + + integer (kind=int_kind) :: & + nt, & ! timestep index for Icepack arrays + i, & ! index for forcing data arrays + bound, & ! bound for subsetting data + dimlen, & ! length of the data arrays + ncid, & ! NetCDF file id + dimid, & ! NetCDF dimension id + status, & ! NetCDF status flag + varid ! NetCDF variable id + + integer (kind=dbl_kind), allocatable :: & + data_time(:) ! array for time array in forcing data + + integer (kind=dbl_kind), dimension(ntime) :: & + model_time ! array for Icepack minutely time + + real (kind=dbl_kind) :: & + model_time0 ! start time for model in seconds since 1970 + + real (kind=dbl_kind), allocatable :: & + data(:) ! data array from file + + character (char_len) :: varname + + character (char_len_long) :: & + filename, & + time_basis ! time basis for data + + integer (kind=int_kind), dimension(ntime, 2) :: & + data_sections ! 2D array for indices corresponding + ! to which data values should be averaged to + ! create the model forcing values + + real (kind=dbl_kind), parameter :: & + Gregorian_year = 365.2425, & ! days in Gregorian year per cf standard + model_miss_val = -9999.00 ! missing value for internal use + + character(len=*), parameter :: subname='(atm_MDF)' + + filename = trim(data_dir)//'/MDF/'//trim(atm_data_file) + + if (atm_data_format /= 'nc') then + call icedrv_system_abort(string=subname//& + ' ERROR: only NetCDF input implemented for atm_MDF', & + file=__FILE__,line=__LINE__) + else +#ifdef USE_NETCDF + ! Open forcing file + status = nf90_open(trim(filename), nf90_nowrite, ncid) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt open netcdf file', & + file=__FILE__,line=__LINE__) + + ! Create array for the time step values in seconds since 1970 + ! CF standard calendar is Gregorian + ! May have strange behavior if dt is not an integer + model_time0 = (year_init - 1970) * Gregorian_year * 24 * 3600 + time0 + do nt = 1, ntime + model_time(nt) = int(model_time0 + dt * nt, kind=dbl_kind) + enddo + + ! Read, average, and interpolate forcing data from each variable + ! Moving average forcing values into model arrays + call load_var_MDF("tas", Tair_data, ncid, model_time) + call load_var_MDF("hus", Qa_data, ncid, model_time) + call load_var_MDF("uas", uatm_data, ncid, model_time) + call load_var_MDF("vas", vatm_data, ncid, model_time) + call load_var_MDF("rlds", flw_data, ncid, model_time) + call load_var_MDF("rsds", fsw_data, ncid, model_time) + + ! Precipitation data is optional + ! Check whether snowfall rate is in the dataset + status = nf90_inq_varid(ncid, "prsn", varid) + if (status /= nf90_noerr) then + write(nu_diag,*) subname + write(nu_diag,*) 'WARNING: no snowfall rate in forcing.'// & + ' Icepack will assume snowfall rate is zero.' + fsnow_data(:) = c0 + else + call load_var_MDF("prsn", fsnow_data, ncid, model_time) + endif + ! Check whether total precipitation rate is in the dataset + status = nf90_inq_varid(ncid, "pr", varid) + if (status /= nf90_noerr) then + write(nu_diag,*) subname + write(nu_diag,*) 'WARNING: no precipitation rate in '// & + 'forcing. Icepack will assume rainfall rate is zero.' + frain_data(:) = c0 + else + call load_var_MDF("pr", frain_data, ncid, model_time) + endif + ! rainfall is total precipitation minus snowfall + ! subject to the constraint that rainfall is non-negative + do nt = 1, ntime + frain_data(nt) = max(frain_data(nt) - fsnow_data(nt), c0) + enddo + +#else + call icedrv_system_abort(string=subname//& + ' ERROR: atm_data_format = "nc" requires USE_NETCDF', & + file=__FILE__,line=__LINE__) +#endif + endif + + end subroutine atm_MDF + +!======================================================================= + +#ifdef USE_NETCDF + subroutine MDF_average(data_var_name, model_var_arr, & + data_var_len, ncid, data_sections, model_miss_val) + + character(len=*), intent(in) :: & + data_var_name ! Name of the variable in the MDF forcing file + + real (kind=dbl_kind), dimension(ntime), intent(out) :: & + model_var_arr ! array to place averaged forcing data in + + integer (kind=int_kind), intent(in) :: & + data_var_len, & ! Size of data array in MDF forcing file + ncid ! NetCDF file id + + integer (kind=int_kind), dimension(ntime, 2) :: & + data_sections ! indices for which data values to average + + real (kind=dbl_kind), intent(in) :: & + model_miss_val ! for when there is no data in a time step + + ! Local variables + real (kind=dbl_kind), dimension(data_var_len) :: & + data_var_arr ! array for data from forcing file + + real (kind=dbl_kind) :: & + work, & ! variable for averaging + data_miss_val, & ! value of missing data + count ! counter for data to average + + integer (kind=int_kind) :: & + status, & ! NetCDF status flag + nt, & ! timestep index for Icepack arrays + i, & ! index for forcing data arrays + varid ! NetCDF variable id + + character(len=*), parameter :: subname='(MDF_average)' + + ! Allocate get data and missing value from file + status = nf90_inq_varid(ncid, trim(data_var_name), varid) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//data_var_name//' var id', & + file=__FILE__,line=__LINE__) + status = nf90_get_att(ncid, varid, "missing_value", data_miss_val) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//data_var_name//' missing value', & + file=__FILE__,line=__LINE__) + status = nf90_get_var(ncid, varid, data_var_arr) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//data_var_name//' values', & + file=__FILE__,line=__LINE__) + + ! For each model time point average non-missing data values + do nt = 1, ntime + count = 0 + work = c0 + do i = data_sections(nt, 1), data_sections(nt, 2) + if (data_var_arr(i) /= data_miss_val) then + work = work + data_var_arr(i) + count = count + 1 + endif + end do + if (count > 0) then + model_var_arr(nt) = work / count + else + model_var_arr(nt) = model_miss_val + endif + end do + + end subroutine MDF_average +#endif + +!======================================================================= + + subroutine MDF_interpolate(model_var_arr, model_miss_val) + + real (kind=dbl_kind), dimension(ntime), intent(inout) :: & + model_var_arr ! array to place averaged forcing data in + + real (kind=dbl_kind), intent(in) :: & + model_miss_val ! for when there is no data in a time step + + integer (kind=int_kind) :: & + mlast, & ! index of last present data + nt, m, & ! model timestep indices + count ! counter for missing values + + character(len=*), parameter :: subname='(MDF_interpolate)' + + ! Interpolate, extrapolate for first and last values + if (model_var_arr(1) == model_miss_val) then + mlast = 0 + else + mlast = 1 + endif + do nt = 2, ntime + if (model_var_arr(nt) == model_miss_val) then + ! Do nothing (i.e., allow nt to increment) unless we're at end + if (nt == ntime) then + do m = mlast + 1, nt + model_var_arr(m) = model_var_arr(mlast) + end do + endif + else if ((nt - mlast) == 1) then + ! No missing data, increment mlast + mlast = nt + else + ! If we're at the start extrapolate to fill + if (mlast==0) then + do m = mlast + 1, nt - 1 + model_var_arr(m) = model_var_arr(nt) + end do + else + ! Interpolate missing data + do m = mlast + 1, nt - 1 + model_var_arr(m) = model_var_arr(mlast) & + + (model_var_arr(nt) - model_var_arr(mlast)) & + * (m - mlast) / (nt - mlast) + end do + endif + mlast = nt + endif + end do + + end subroutine MDF_interpolate +!======================================================================= + + subroutine load_var_MDF(data_var_name, model_var_arr, ncid, & + model_time) + + character(len=*), intent(in) :: & + data_var_name ! Name of the variable in the MDF forcing file + + real (kind=dbl_kind), dimension(ntime), intent(out) :: & + model_var_arr ! array to place forcing data in + + integer (kind=int_kind), intent(in) :: & + ncid ! NetCDF file id + + integer (kind=dbl_kind), dimension(ntime), intent(in) :: & + model_time ! model time array + + ! Local variables + + integer (kind=int_kind) :: & + nt, & ! timestep index for Icepack arrays + i, & ! index for forcing data arrays + bound, & ! bound for subsetting data + dimlen, & ! length of the data arrays + dimid, & ! NetCDF dimension id + status, & ! NetCDF status flag + nvardims,& ! number of dimensions for variable + varid ! NetCDF variable id + + integer (kind=dbl_kind), allocatable :: & + data_time(:) ! array for time array in forcing data + + integer, dimension(1) :: & + vardimids ! dimension id for variable + + character (char_len) :: & + calendar_type, & ! data calendar type + dimname ! name for variables dimension + + character (char_len_long) :: & + time_basis ! time basis for data + + integer (kind=int_kind), dimension(ntime, 2) :: & + data_sections ! 2D array for indices corresponding + ! to which data values should be averaged to + ! create the model forcing values + + real (kind=dbl_kind), parameter :: & + Gregorian_year = 365.2425, & ! days in Gregorian year per cf standard + model_miss_val = -9999.00 ! missing value for internal use + + character(len=*), parameter :: subname='(load_var_MDF)' + +#ifdef USE_NETCDF + + ! Get varid and missing value from file + status = nf90_inq_varid(ncid, trim(data_var_name), varid) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//data_var_name//' var id', & + file=__FILE__,line=__LINE__) + ! Get information about the dimension for this variable + status = nf90_inquire_variable(ncid, varid, ndims=nvardims) + if (nvardims /= 1) call icedrv_system_abort(& + string=subname//data_var_name//' has more than 1 dimension', & + file=__FILE__,line=__LINE__) + status = nf90_inquire_variable(ncid, varid, dimids=vardimids) + status = nf90_inquire_dimension(ncid, vardimids(1), & + name=dimname, len=dimlen) + ! Check that dimname matches pattern + if (dimname(1:4) /= 'time') call icedrv_system_abort(& + string=subname//data_var_name//' dimension name is not timeXXXX', & + file=__FILE__,line=__LINE__) + if (verify(trim(dimname(5:)), "0123456789") /= 0) call icedrv_system_abort(& + string=subname//data_var_name//' dimension name is not timeXXXX', & + file=__FILE__,line=__LINE__) + allocate (data_time(dimlen)) + ! Check that cadence variable exists and calendars match + status = nf90_inq_varid(ncid, trim(dimname), varid) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//trim(dimname)//' var id', & + file=__FILE__,line=__LINE__) + status = nf90_get_att(ncid, varid, "calendar", calendar_type) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get calendar attribute', & + file=__FILE__,line=__LINE__) + ! In future this check could be replaced with calendar matching + if (calendar_type /= "standard" .or. .not. use_leap_years) then + call icedrv_system_abort(& + string=subname//'Forcing calendar not standard or not using leap years',& + file=__FILE__,line=__LINE__) + endif + ! Get the time array + !! Note, in the file the value is actually unsigned, need to make sure this + ! doesn't cause issues since Fortran 90 doesn't support unsigned ints. + status = nf90_get_var(ncid, varid, data_time) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt read '//trim(dimname)//' values', & + file=__FILE__,line=__LINE__) + ! Convert the data time from minutes into seconds for compatability w/ icepack + data_time = data_time * 60 + + ! Check that the time basis in forcing file is correct + status = nf90_get_att(ncid, varid, "units", time_basis) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt get '//trim(dimname)//' units', & + file=__FILE__,line=__LINE__) + if (time_basis /= "minutes since 1970-01-01 00:00:00") then + call icedrv_system_abort(& + string=subname//'Time basis is not minutes since 1970',& + file=__FILE__,line=__LINE__) + endif + + ! Check that we are not extrapolating forcing outside of time bounds + if (model_time(1) < data_time(1)) call icedrv_system_abort(& + string=subname//'Simulation starts before forcing',& + file=__FILE__,line=__LINE__) + if (model_time(ntime) > data_time(dimlen)) call icedrv_system_abort(& + string=subname//'Simulation ends after forcing',& + file=__FILE__,line=__LINE__) + + ! data_sections is a 2D array where the first dimension + ! is the same length as model_time. The 1D array at each index + ! contains the start and stop indices of the data to be averaged + ! into each model timestep + ! Get the first start index + bound = model_time(1) - (model_time(2) - model_time(1))/2 + i = 1 + do while (data_time(i) < bound) + i = i + 1 + end do + data_sections(1, 1) = i + do nt = 1, ntime - 1 + ! Bound is halfway between this time step and the next + bound = (model_time(nt + 1) + model_time(nt))/2 + do while (data_time(i) < bound) + i = i + 1 + end do ! i - 1 is now the last element in timestep nt + data_sections(nt, 2) = i - 1 + data_sections(nt + 1, 1) = i + end do + ! Get the last index + bound = model_time(ntime) + (model_time(ntime) - model_time(ntime - 1))/2 + i = dimlen + do while (data_time(i) > bound) + i = i - 1 + end do + data_sections(ntime, 2) = i + + model_var_arr(:) = model_miss_val + + ! Moving average forcing values into model arrays + call MDF_average(data_var_name, model_var_arr, dimlen, ncid, & + data_sections, model_miss_val) + ! Linearly interpolate missing values + call MDF_interpolate(model_var_arr, model_miss_val) + +#else + call icedrv_system_abort(string=subname//& + ' load_var_MDF requires USE_NETCDF', & + file=__FILE__,line=__LINE__) +#endif + + end subroutine load_var_MDF + !======================================================================= subroutine ocn_NICE @@ -1070,7 +1538,100 @@ subroutine ocn_ISPOL qdp_data (i) = qdp (i) end do - end subroutine ocn_ISPOL + end subroutine ocn_ISPOL + +!======================================================================= + + subroutine ocn_MDF + + integer (kind=int_kind) :: & + nt, & ! timestep index for Icepack arrays + i, & ! index for forcing data arrays + bound, & ! bound for subsetting data + dimlen, & ! length of the data arrays + ncid, & ! NetCDF file id + dimid, & ! NetCDF dimension id + status, & ! NetCDF status flag + varid ! NetCDF variable id + + integer (kind=dbl_kind), allocatable :: & + data_time(:) ! array for time array in forcing data + + integer (kind=dbl_kind), dimension(ntime) :: & + model_time ! array for Icepack minutely time + + real (kind=dbl_kind) :: & + model_time0 ! start time for model in seconds since 1970 + + real (kind=dbl_kind), allocatable :: & + data(:) ! data array from file + + character (char_len) :: varname + + character (char_len_long) :: & + filename, & + time_basis ! time basis for data + + integer (kind=int_kind), dimension(ntime, 2) :: & + data_sections ! 2D array for indices corresponding + ! to which data values should be averaged to + ! create the model forcing values + + real (kind=dbl_kind), parameter :: & + Gregorian_year = 365.2425, & ! days in Gregorian year per cf standard + model_miss_val = -9999.00, & ! missing value for internal use + leg4_end_time = 1596034800, &! end of leg 4 in seconds since 1970 + leg5_start_time= 1598451600 ! start of leg 5 in seconds since 1970 + + character(len=*), parameter :: subname='(ocn_MDF)' + + filename = trim(data_dir)//'/MDF/'//trim(ocn_data_file) + + if (ocn_data_format /= 'nc') then + call icedrv_system_abort(string=subname//& + ' ERROR: only NetCDF input implemented for ocn_MDF', & + file=__FILE__,line=__LINE__) + else +#ifdef USE_NETCDF + ! Open forcing file + status = nf90_open(trim(filename), nf90_nowrite, ncid) + if (status /= nf90_noerr) call icedrv_system_abort(& + string=subname//'Couldnt open netcdf file', & + file=__FILE__,line=__LINE__) + + ! Create array for the time step values in seconds since 1970 + ! CF standard calendar is Gregorian + ! May have strange behavior if dt is not an integer + model_time0 = (year_init - 1970) * Gregorian_year * 24 * 3600 + time0 + do nt = 1, ntime + model_time(nt) = int(model_time0 + dt * nt, kind=dbl_kind) + enddo + + ! Warn if simulation includes leg 4-5 transition + if ((model_time(1) < leg5_start_time) .and. & + (model_time(ntime) > leg4_end_time) .and. & + (index(ocn_data_file, 'MOSAiC') > 0)) then + write(nu_diag,*) subname + write(nu_diag,*) 'WARNING: Forcing may be from MOSAiC '// & + 'and time includes MOSAIC leg 4-5 repositioning. ' // & + 'If so, forcing interpolation is not valid.' + endif + + ! Read, average, and interpolate forcing data from each variable + ! Moving average forcing values into model arrays + call load_var_MDF("so", sss_data, ncid, model_time) + call load_var_MDF("mlotst", hmix_data, ncid, model_time) + call load_var_MDF("hfsot", qdp_data, ncid, model_time) + call load_var_MDF("tos", sst_data, ncid, model_time) + +#else + call icedrv_system_abort(string=subname//& + ' ERROR: ocn_data_format = "nc" requires USE_NETCDF', & + file=__FILE__,line=__LINE__) +#endif + endif + + end subroutine ocn_MDF !======================================================================= diff --git a/configuration/driver/icedrv_history.F90 b/configuration/driver/icedrv_history.F90 index 049566b7..a471c016 100644 --- a/configuration/driver/icedrv_history.F90 +++ b/configuration/driver/icedrv_history.F90 @@ -13,6 +13,7 @@ module icedrv_history use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted use icepack_intfc, only: icepack_query_parameters, icepack_query_tracer_sizes use icepack_intfc, only: icepack_query_tracer_flags, icepack_query_tracer_indices + use icepack_intfc, only: icepack_query_tracer_indices use icedrv_system, only: icedrv_system_abort implicit none @@ -49,7 +50,10 @@ subroutine history_write() use icedrv_flux, only: evap, fsnow, frain, frazil use icedrv_flux, only: fswabs, flw, flwout, fsens, fsurf, flat use icedrv_flux, only: Tair, Qa, fsw, fcondtop - use icedrv_flux, only: meltt, meltb, meltl, snoice + use icedrv_flux, only: meltt, meltb, meltl, melts, snoice + use icedrv_flux, only: dpnd_flushn, dpnd_exponn, dpnd_freebdn, dpnd_initialn, dpnd_dlidn + use icedrv_flux, only: dpnd_flush, dpnd_expon, dpnd_freebd, dpnd_initial, dpnd_dlid + use icedrv_flux, only: dpnd_melt, dpnd_ridge use icedrv_flux, only: dsnow, congel, sst, sss, Tf, fhocn use icedrv_arrays_column, only: d_afsd_newi, d_afsd_latg, d_afsd_latm, d_afsd_wave, d_afsd_weld #ifdef USE_NETCDF @@ -69,7 +73,9 @@ subroutine history_write() count1(1), count2(2), count3(3), count4(4), & ! cdf start/count arrays varid, & ! cdf varid status, & ! cdf status flag - iflag ! history file attributes + iflag, & ! history file attributes + numvars, & ! temporary for writing fields + nt_apnd, nt_hpnd, nt_ipnd ! pond tracer indices character (len=8) :: & cdate ! date string @@ -79,7 +85,7 @@ subroutine history_write() real (kind=dbl_kind),allocatable :: & value1(:), value2(:,:), value3(:,:,:), value4(:,:,:,:) ! temporary - integer (kind=dbl_kind), parameter :: num_2d = 32 + integer (kind=dbl_kind), parameter :: num_2d = 33 character(len=16), parameter :: fld_2d(num_2d) = & (/ 'aice ', 'vice ', 'vsno ', & 'uvel ', 'vvel ', 'divu ', & @@ -91,20 +97,36 @@ subroutine history_write() 'fsw ', 'fcondtop ', 'meltt ', & 'meltb ', 'meltl ', 'snoice ', & 'dsnow ', 'congel ', 'sst ', & - 'sss ', 'Tf ', 'fhocn ' /) + 'sss ', 'Tf ', 'fhocn ', & + 'melts ' /) + + integer (kind=dbl_kind), parameter :: num_2d_pond = 10 + character(len=16), parameter :: fld_2d_pond(num_2d_pond) = & + (/ 'apnd ', 'hpnd ', 'ipnd ', & + 'dpnd_flush ', 'dpnd_expon ', 'dpnd_freebd ', & + 'dpnd_initial ', 'dpnd_dlid ', 'dpnd_melt ', & + 'dpnd_ridge ' /) integer (kind=dbl_kind), parameter :: num_3d_ncat = 3 character(len=16), parameter :: fld_3d_ncat(num_3d_ncat) = & (/ 'aicen ', 'vicen ', 'vsnon ' /) logical (kind=log_kind) :: & - tr_fsd ! flag for tracing fsd + tr_fsd, & ! flag for tracing fsd + tr_pnd, & ! flag for tracing ponds + tr_pnd_topo ! flag for tracing topo ponds integer (kind=dbl_kind), parameter :: num_3d_nfsd = 5 character(len=16), parameter :: fld_3d_nfsd(num_3d_nfsd) = & (/ 'd_afsd_newi ', 'd_afsd_latg ', 'd_afsd_latm ', & 'd_afsd_wave ', 'd_afsd_weld ' /) + integer (kind=dbl_kind), parameter :: num_3d_pond = 8 + character(len=16), parameter :: fld_3d_pond(num_3d_pond) = & + (/ 'apndn ', 'hpndn ', 'ipndn ', & + 'dpnd_flushn ', 'dpnd_exponn ', 'dpnd_freebdn ', & + 'dpnd_initialn ', 'dpnd_dlidn ' /) + integer (kind=dbl_kind), parameter :: num_3d_ntrcr = 1 character(len=16), parameter :: fld_3d_ntrcr(num_3d_ntrcr) = & (/ 'trcr ' /) @@ -119,7 +141,8 @@ subroutine history_write() #ifdef USE_NETCDF call icepack_query_tracer_sizes(ntrcr_out=ntrcr) - call icepack_query_tracer_flags(tr_fsd_out=tr_fsd) + call icepack_query_tracer_flags(tr_fsd_out=tr_fsd, tr_pond_out=tr_pnd, & + tr_pond_topo_out=tr_pnd_topo) if (first_call) then timcnt = 0 write(hist_file,'(a,i8.8,a)') './history/icepack.h.',idate,'.nc' @@ -176,8 +199,10 @@ subroutine history_write() status = nf90_put_att(ncid,varid,'calendar','NoLeap') if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: put_att calendar noleap') elseif (use_leap_years) then - status = nf90_put_att(ncid,varid,'calendar','Gregorian') - if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: put_att calendar gregorian') + status = nf90_put_att(ncid,varid,'calendar','proleptic_gregorian') + if (status /= nf90_noerr) then + call icedrv_system_abort(string=subname//' ERROR: put_att calendar proleptic_gregorian') + endif else call icedrv_system_abort(string=subname//' ERROR: invalid calendar settings') endif @@ -196,6 +221,17 @@ subroutine history_write() if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR in def_var '//trim(fld_2d(n))) enddo + if (tr_pnd) then + numvars = num_2d_pond + ! tcraig, July 2025, do not write most of the pond fields for topo ponds, they are not validated yet + ! this is a temporary implementation, hardcode to write the first 3 fields only + if (tr_pnd_topo) numvars=3 + do n = 1,numvars + status = nf90_def_var(ncid,trim(fld_2d_pond(n)),NF90_DOUBLE,dimid2,varid) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR in def_var '//trim(fld_2d_pond(n))) + enddo + endif ! tr_pnd + ! 3d ncat fields dimid3(1) = nxid @@ -207,6 +243,17 @@ subroutine history_write() if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR in def_var '//trim(fld_3d_ncat(n))) enddo + if (tr_pnd) then + numvars = num_3d_pond + ! tcraig, July 2025, do not write most of the pond fields for topo ponds, they are not validated yet + ! this is a temporary implementation, hardcode to write the first 3 fields only + if (tr_pnd_topo) numvars=3 + do n = 1,numvars + status = nf90_def_var(ncid,trim(fld_3d_pond(n)),NF90_DOUBLE,dimid3,varid) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR in def_var '//trim(fld_3d_pond(n))) + enddo + endif ! tr_pnd + if (tr_fsd) then ! 3d nfsd fields @@ -333,6 +380,7 @@ subroutine history_write() if (trim(fld_2d(n)) == 'meltt') value2(1:count2(1),1) = meltt(1:count2(1)) if (trim(fld_2d(n)) == 'meltb') value2(1:count2(1),1) = meltb(1:count2(1)) if (trim(fld_2d(n)) == 'meltl') value2(1:count2(1),1) = meltl(1:count2(1)) + if (trim(fld_2d(n)) == 'melts') value2(1:count2(1),1) = melts(1:count2(1)) if (trim(fld_2d(n)) == 'snoice') value2(1:count2(1),1) = snoice(1:count2(1)) if (trim(fld_2d(n)) == 'dsnow') value2(1:count2(1),1) = dsnow(1:count2(1)) if (trim(fld_2d(n)) == 'congel') value2(1:count2(1),1) = congel(1:count2(1)) @@ -349,6 +397,44 @@ subroutine history_write() deallocate(value2) enddo + ! 2d pond fields + if (tr_pnd) then + call icepack_query_tracer_indices( & + nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, nt_ipnd_out=nt_ipnd) + + start2(1) = 1 + count2(1) = nx + start2(2) = timcnt + count2(2) = 1 + + numvars = num_2d_pond + ! tcraig, July 2025, do not write most of the pond fields for topo ponds, they are not validated yet + ! this is a temporary implementation, hardcode to write the first 3 fields only + if (tr_pnd_topo) numvars=3 + do n = 1,numvars + allocate(value2(count2(1),1)) + + value2 = -9999._dbl_kind + if (trim(fld_2d_pond(n)) == 'apnd') value2(1:count2(1),1) = trcr(1:count2(1),nt_apnd) + if (trim(fld_2d_pond(n)) == 'hpnd') value2(1:count2(1),1) = trcr(1:count2(1),nt_hpnd) + if (trim(fld_2d_pond(n)) == 'ipnd') value2(1:count2(1),1) = trcr(1:count2(1),nt_ipnd) + if (trim(fld_2d_pond(n)) == 'dpnd_flush' ) value2(1:count2(1),1) = dpnd_flush (1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_expon' ) value2(1:count2(1),1) = dpnd_expon (1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_freebd' ) value2(1:count2(1),1) = dpnd_freebd (1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_initial') value2(1:count2(1),1) = dpnd_initial(1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_dlid' ) value2(1:count2(1),1) = dpnd_dlid (1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_melt' ) value2(1:count2(1),1) = dpnd_melt (1:count2(1)) + if (trim(fld_2d_pond(n)) == 'dpnd_ridge' ) value2(1:count2(1),1) = dpnd_ridge (1:count2(1)) + + status = nf90_inq_varid(ncid,trim(fld_2d_pond(n)),varid) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: inq_var '//trim(fld_2d_pond(n))) + status = nf90_put_var(ncid,varid,value2,start=start2,count=count2) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: put_var '//trim(fld_2d_pond(n))) + + deallocate(value2) + enddo + endif !tr_pnd + ! 3d ncat fields start3(1) = 1 @@ -374,6 +460,44 @@ subroutine history_write() deallocate(value3) enddo + ! 3d pond fields + if (tr_pnd) then + call icepack_query_tracer_indices( & + nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, nt_ipnd_out=nt_ipnd) + + start3(1) = 1 + count3(1) = nx + start3(2) = 1 + count3(2) = ncat + start3(3) = timcnt + count3(3) = 1 + + numvars = num_3d_pond + ! tcraig, July 2025, do not write most of the pond fields for topo ponds, they are not validated yet + ! this is a temporary implementation, hardcode to write the first 3 fields only + if (tr_pnd_topo) numvars=3 + do n = 1,numvars + allocate(value3(count3(1),count3(2),1)) + + value3 = -9999._dbl_kind + if (trim(fld_3d_pond(n)) == 'apndn') value3(1:count3(1),1:count3(2),1) = trcrn(1:count3(1),nt_apnd,1:count3(2)) + if (trim(fld_3d_pond(n)) == 'hpndn') value3(1:count3(1),1:count3(2),1) = trcrn(1:count3(1),nt_hpnd,1:count3(2)) + if (trim(fld_3d_pond(n)) == 'ipndn') value3(1:count3(1),1:count3(2),1) = trcrn(1:count3(1),nt_ipnd,1:count3(2)) + if (trim(fld_3d_pond(n)) == 'dpnd_flushn' ) value3(1:count3(1),1:count3(2),1) = dpnd_flushn (1:count3(1),1:count3(2)) + if (trim(fld_3d_pond(n)) == 'dpnd_exponn' ) value3(1:count3(1),1:count3(2),1) = dpnd_exponn (1:count3(1),1:count3(2)) + if (trim(fld_3d_pond(n)) == 'dpnd_freebdn' ) value3(1:count3(1),1:count3(2),1) = dpnd_freebdn (1:count3(1),1:count3(2)) + if (trim(fld_3d_pond(n)) == 'dpnd_initialn') value3(1:count3(1),1:count3(2),1) = dpnd_initialn(1:count3(1),1:count3(2)) + if (trim(fld_3d_pond(n)) == 'dpnd_dlidn' ) value3(1:count3(1),1:count3(2),1) = dpnd_dlidn (1:count3(1),1:count3(2)) + + status = nf90_inq_varid(ncid,trim(fld_3d_pond(n)),varid) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: inq_var '//trim(fld_3d_pond(n))) + status = nf90_put_var(ncid,varid,value3,start=start3,count=count3) + if (status /= nf90_noerr) call icedrv_system_abort(string=subname//' ERROR: put_var '//trim(fld_3d_pond(n))) + + deallocate(value3) + enddo + endif !tr_pnd + if (tr_fsd) then ! 3d nfsd fields diff --git a/configuration/driver/icedrv_init.F90 b/configuration/driver/icedrv_init.F90 index 7ba890e7..133683dd 100644 --- a/configuration/driver/icedrv_init.F90 +++ b/configuration/driver/icedrv_init.F90 @@ -10,6 +10,7 @@ module icedrv_init use icedrv_constants, only: nu_diag, ice_stdout, nu_diag_out, nu_nml use icedrv_constants, only: c0, c1, c2, c3, p2, p5 use icedrv_domain_size, only: nx + use icedrv_flux, only: sst_init use icepack_intfc, only: icepack_init_parameters use icepack_intfc, only: icepack_init_fsd use icepack_intfc, only: icepack_init_tracer_flags @@ -43,6 +44,12 @@ module icedrv_init lmask_n, & ! northern hemisphere mask lmask_s ! southern hemisphere mask + real (kind=dbl_kind), public :: & + hi_init_slab, & ! initial ice thickness for slab cell (nx=2) + hsno_init_slab, & ! initial snow thickness for slab cell (nx=2) + hbar_init_itd, & ! hbar for ice thickness for itd cell (nx=3) + hsno_init_itd ! initial snow thickness for itd cell (nx=3) + !======================================================================= contains @@ -66,6 +73,7 @@ subroutine input_data use icedrv_restart_shared, only: restart, restart_dir, restart_file, restart_format use icedrv_flux, only: l_mpond_fresh, cpl_bgc use icedrv_flux, only: default_season + use icedrv_flux, only: sss_fixed, qdp_fixed, hmix_fixed use icedrv_forcing, only: precip_units, fyear_init, ycycle use icedrv_forcing, only: atm_data_type, ocn_data_type, bgc_data_type use icedrv_forcing, only: atm_data_file, ocn_data_file, bgc_data_file @@ -74,6 +82,7 @@ subroutine input_data use icedrv_forcing, only: data_dir use icedrv_forcing, only: oceanmixed_ice, restore_ocn, trestore use icedrv_forcing, only: snw_ssp_table, lateral_flux_type + use icedrv_forcing, only: precalc_forc ! local variables @@ -90,10 +99,11 @@ subroutine input_data real (kind=dbl_kind) :: ustar_min, albicev, albicei, albsnowv, albsnowi, & ahmax, R_ice, R_pnd, R_snw, dT_mlt, rsnw_mlt, ksno, hi_min, Tliquidus_max, & mu_rdg, hs0, dpscale, rfracmin, rfracmax, pndaspect, hs1, hp1, & + apnd_sl, tscale_pnd_drain, itd_area_min, itd_mass_min, & a_rapid_mode, Rac_rapid_mode, aspect_rapid_mode, dSdt_slow_mode, & phi_c_slow_mode, phi_i_mushy, kalg, emissivity, floediam, hfrazilmin, & rsnw_fall, rsnw_tmax, rhosnew, rhosmin, rhosmax, & - windmin, drhosdwind, snwlvlfac + windmin, drhosdwind, snwlvlfac, snw_growth_wet, drsnw_min, snwliq_max integer (kind=int_kind) :: ktherm, kstrength, krdg_partic, krdg_redist, & natmiter, kitd, kcatbound @@ -113,18 +123,18 @@ subroutine input_data real (kind=dbl_kind) :: ice_ref_salinity logical (kind=log_kind) :: calc_Tsfc, formdrag, highfreq, calc_strair, calc_dragio - logical (kind=log_kind) :: conserv_check + logical (kind=log_kind) :: conserv_check, semi_implicit_Tsfc, vapor_flux_correction integer (kind=int_kind) :: ntrcr 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_lvl, tr_pond_topo, wave_spec + logical (kind=log_kind) :: tr_pond_lvl, tr_pond_topo, tr_pond_sealvl, 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) :: rplvl, rptopo + real (kind=real_kind) :: rplvl, rptopo, rpsealvl real (kind=dbl_kind) :: Cf, puny character(len=*), parameter :: subname='(input_data)' @@ -139,7 +149,9 @@ subroutine input_data ice_ic, restart, restart_dir, restart_file, & restart_format, & dumpfreq, diagfreq, diag_file, cpl_bgc, & - conserv_check, history_format + conserv_check, history_format, & + hi_init_slab, hsno_init_slab, hbar_init_itd, hsno_init_itd, & + sst_init, itd_area_min, itd_mass_min namelist /grid_nml/ & kcatbound @@ -148,7 +160,8 @@ subroutine input_data kitd, ktherm, ksno, conduct, & a_rapid_mode, Rac_rapid_mode, aspect_rapid_mode, & dSdt_slow_mode, phi_c_slow_mode, phi_i_mushy, & - floediam, hfrazilmin, Tliquidus_max, hi_min + floediam, hfrazilmin, Tliquidus_max, hi_min, & + tscale_pnd_drain namelist /dynamics_nml/ & kstrength, krdg_partic, krdg_redist, mu_rdg, & @@ -164,11 +177,13 @@ subroutine input_data namelist /ponds_nml/ & hs0, dpscale, frzpnd, & rfracmin, rfracmax, pndaspect, hs1, & - hp1 + hp1, apnd_sl + namelist /snow_nml/ & snwredist, snwgrain, rsnw_fall, rsnw_tmax, & rhosnew, rhosmin, rhosmax, snwlvlfac, & - windmin, drhosdwind, use_smliq_pnd, snw_aging_table + windmin, drhosdwind, use_smliq_pnd, snw_aging_table, & + snw_growth_wet, drsnw_min, snwliq_max namelist /forcing_nml/ & atmbndy, calc_strair, calc_Tsfc, & @@ -176,16 +191,19 @@ subroutine input_data fbot_xfer_type, oceanmixed_ice, emissivity, & formdrag, highfreq, natmiter, & atmiter_conv, calc_dragio, congel_freeze, & - tfrz_option, saltflux_option, ice_ref_salinity, & - default_season, wave_spec_type, wave_height_type, & - cpl_frazil, & + tfrz_option, saltflux_option, ice_ref_salinity,& + cpl_frazil, default_season, & + wave_spec_type, wave_height_type, & precip_units, fyear_init, ycycle, & atm_data_type, ocn_data_type, bgc_data_type, & lateral_flux_type, & atm_data_file, ocn_data_file, bgc_data_file, & ice_data_file, & atm_data_format, ocn_data_format, bgc_data_format, & - data_dir, trestore, restore_ocn + data_dir, trestore, restore_ocn, & + sss_fixed, qdp_fixed, hmix_fixed, & + precalc_forc, semi_implicit_Tsfc, & + vapor_flux_correction namelist /tracer_nml/ & tr_iage, & @@ -193,6 +211,7 @@ subroutine input_data tr_lvl, & tr_pond_lvl, & tr_pond_topo, & + tr_pond_sealvl, & tr_snow, & tr_aero, & tr_fsd, & @@ -218,7 +237,10 @@ subroutine input_data dpscale_out=dpscale, frzpnd_out=frzpnd, & rfracmin_out=rfracmin, rfracmax_out=rfracmax, & pndaspect_out=pndaspect, hs1_out=hs1, hp1_out=hp1, & + apnd_sl_out=apnd_sl, tscale_pnd_drain_out=tscale_pnd_drain, & ktherm_out=ktherm, calc_Tsfc_out=calc_Tsfc, & + semi_implicit_Tsfc_out=semi_implicit_Tsfc, & + vapor_flux_correction_out=vapor_flux_correction, & floediam_out=floediam, hfrazilmin_out=hfrazilmin, & update_ocn_f_out = update_ocn_f, cpl_frazil_out = cpl_frazil, & conduct_out=conduct, a_rapid_mode_out=a_rapid_mode, & @@ -238,7 +260,9 @@ subroutine input_data 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, & - snw_aging_table_out=snw_aging_table) + snw_aging_table_out=snw_aging_table, snw_growth_wet_out=snw_growth_wet, & + drsnw_min_out=drsnw_min, snwliq_max_out=snwliq_max, & + itd_area_min_out=itd_area_min, itd_mass_min_out=itd_mass_min) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -267,6 +291,11 @@ subroutine input_data history_format = 'none' ! if 'nc', write history files. Otherwise do nothing ice_ic = 'default' ! initial conditions are specified in the code ! otherwise, the filename for reading restarts + hi_init_slab = c2 ! initial ice thickness for slab cell (nx=2) + hsno_init_slab = c0 ! initial snow thickness for slab cell (nx=2) + hbar_init_itd = c3 ! hbar for ice thickness for itd cell (nx=3) + hsno_init_itd = 0.25_dbl_kind ! initial snow thickness for itd cell (nx=3) + sst_init = -1.8_dbl_kind ! initial mixed layer temperature (all cells) ndtd = 1 ! dynamic time steps per thermodynamic time step l_mpond_fresh = .false. ! logical switch for including meltpond freshwater ! flux feedback to ocean model @@ -294,6 +323,7 @@ subroutine input_data restore_ocn = .false. ! restore sst if true trestore = 90 ! restoring timescale, days (0 instantaneous) snw_ssp_table = 'test' ! snow table type, test or snicar + precalc_forc = .false. ! whether to precalculate forcing ! extra tracers tr_iage = .false. ! ice age @@ -301,6 +331,7 @@ subroutine input_data tr_lvl = .false. ! level ice tr_pond_lvl = .false. ! level-ice melt ponds tr_pond_topo = .false. ! topographic melt ponds + tr_pond_sealvl = .false. ! sealvl melt ponds tr_snow = .false. ! snow tracers (wind redistribution, metamorphosis) tr_aero = .false. ! aerosols tr_fsd = .false. ! floe size distribution @@ -485,13 +516,15 @@ subroutine input_data rplvl = c0 rptopo = c0 + rpsealvl = c0 if (tr_pond_lvl ) rplvl = c1 if (tr_pond_topo) rptopo = c1 + if (tr_pond_sealvl) rpsealvl = c1 tr_pond = .false. ! explicit melt ponds - if (rplvl + rptopo > puny) tr_pond = .true. + if (rplvl + rptopo + rpsealvl > puny) tr_pond = .true. - if (rplvl + rptopo > c1 + puny) then + if (rplvl + rptopo + rpsealvl > c1 + puny) then write (nu_diag,*) 'WARNING: Must use only one melt pond scheme' call icedrv_system_abort(file=__FILE__,line=__LINE__) endif @@ -650,27 +683,21 @@ subroutine input_data endif wave_spec = .false. - if (tr_fsd .and. (trim(wave_spec_type) /= 'none') .and. & - (trim(wave_height_type) /= 'none')) then - wave_spec = .true. - end if - if (tr_fsd .and. (trim(wave_spec_type) == 'none') .and. & - (trim(wave_height_type) == 'none')) then - write (nu_diag,*) 'WARNING: tr_fsd=T but wave_spec=F - not recommended' - endif - if (tr_fsd .and. & - ((trim(wave_spec_type)=='none').and. & - (trim(wave_height_type)/='none'))) then - write (nu_diag,*) 'WARNING: Wave_spec_type=none, wave_height_type must also = none' - call icedrv_system_abort(file=__FILE__,line=__LINE__) - endif - if (tr_fsd .and. & - ((trim(wave_spec_type)/='none').and. & - (trim(wave_height_type)=='none'))) then - write (nu_diag,*) 'WARNING: set wave_height_type=internal or coupled' - call icedrv_system_abort(file=__FILE__,line=__LINE__) + if (tr_fsd) then + if (trim(wave_spec_type) /= 'none') then + if (trim(wave_height_type) /= 'none') wave_spec = .true. + if (trim(wave_height_type) /= 'internal') then + write (nu_diag,*) 'WARNING: set wave_height_type=internal or coupled' + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif + endif + if (.not.(wave_spec)) then + write (nu_diag,*) 'WARNING: tr_fsd=T but wave_spec=F - not recommended' + if (trim(wave_height_type) /= 'none') then + write (nu_diag,*) 'WARNING: Wave_spec=F, wave_height_type/=none, wave_sig_ht = 0' + endif + endif endif - !----------------------------------------------------------------- ! spew @@ -694,7 +721,14 @@ subroutine input_data write(nu_diag,1030) ' restart_format = ', trim(restart_format) write(nu_diag,1030) ' history_format = ', trim(history_format) write(nu_diag,1030) ' ice_ic = ', trim(ice_ic) + write(nu_diag,1005) ' hi_init_slab = ', hi_init_slab + write(nu_diag,1005) ' hsno_init_slab = ', hsno_init_slab + write(nu_diag,1005) ' hbar_init_itd = ', hbar_init_itd + write(nu_diag,1005) ' hsno_init_itd = ', hsno_init_itd + write(nu_diag,1005) ' sst_init = ', sst_init write(nu_diag,1010) ' conserv_check = ', conserv_check + write(nu_diag,1000) ' itd_area_min = ', itd_area_min + write(nu_diag,1000) ' itd_mass_min = ', itd_mass_min write(nu_diag,1020) ' kitd = ', kitd write(nu_diag,1020) ' kcatbound = ', kcatbound write(nu_diag,1020) ' ndtd = ', ndtd @@ -741,13 +775,15 @@ subroutine input_data write(nu_diag,1000) ' rfracmin = ', rfracmin write(nu_diag,1000) ' rfracmax = ', rfracmax - if (tr_pond_lvl) then + if (tr_pond_lvl .or. tr_pond_sealvl) then write(nu_diag,1000) ' hs1 = ', hs1 write(nu_diag,1000) ' dpscale = ', dpscale write(nu_diag,1030) ' frzpnd = ', trim(frzpnd) endif if (tr_pond .and. .not. tr_pond_lvl) & write(nu_diag,1000) ' pndaspect = ', pndaspect + if (tr_pond_sealvl) & + write(nu_diag,1000) ' apnd_sl = ', apnd_sl if (tr_snow) then write(nu_diag,1030) ' snwredist = ', trim(snwredist) @@ -762,6 +798,9 @@ subroutine input_data write(nu_diag,1000) ' windmin = ', windmin write(nu_diag,1000) ' drhosdwind = ', drhosdwind write(nu_diag,1000) ' snwlvlfac = ', snwlvlfac + write(nu_diag,1000) ' snw_growth_wet = ', snw_growth_wet + write(nu_diag,1000) ' drsnw_min = ', drsnw_min + write(nu_diag,1000) ' snwliq_max = ', snwliq_max endif write(nu_diag,1020) ' ktherm = ', ktherm @@ -776,6 +815,7 @@ subroutine input_data write(nu_diag,1005) ' phi_c_slow_mode = ', phi_c_slow_mode write(nu_diag,1005) ' phi_i_mushy = ', phi_i_mushy write(nu_diag,1005) ' Tliquidus_max = ', Tliquidus_max + write(nu_diag,1005) ' tscale_pnd_drain = ', tscale_pnd_drain endif write(nu_diag,1030) ' atmbndy = ', trim(atmbndy) @@ -786,6 +826,8 @@ subroutine input_data write(nu_diag,1010) ' calc_strair = ', calc_strair write(nu_diag,1010) ' calc_Tsfc = ', calc_Tsfc write(nu_diag,1010) ' calc_dragio = ', calc_dragio + write(nu_diag,1010) ' semi_implicit_Tsfc = ', semi_implicit_Tsfc + write(nu_diag,1010) ' vapor_flux_correction = ', vapor_flux_correction write(nu_diag,1005) ' floediam = ', floediam write(nu_diag,1005) ' hfrazilmin = ', hfrazilmin @@ -799,6 +841,7 @@ subroutine input_data write(nu_diag,1030) ' ocn_data_file = ', trim(ocn_data_file) write(nu_diag,1030) ' bgc_data_file = ', trim(bgc_data_file) write(nu_diag,1030) ' ice_data_file = ', trim(ice_data_file) + write(nu_diag,1010) ' precalc_forc = ', precalc_forc if (trim(atm_data_type)=='default') & write(nu_diag,1030) ' default_season = ', trim(default_season) @@ -830,6 +873,7 @@ subroutine input_data write(nu_diag,1010) ' tr_lvl = ', tr_lvl 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_pond_sealvl = ', tr_pond_sealvl write(nu_diag,1010) ' tr_snow = ', tr_snow write(nu_diag,1010) ' tr_aero = ', tr_aero write(nu_diag,1010) ' tr_fsd = ', tr_fsd @@ -875,13 +919,9 @@ subroutine input_data nt_apnd = ntrcr ntrcr = ntrcr + 1 nt_hpnd = ntrcr - if (tr_pond_lvl) then + if (tr_pond_lvl .or. tr_pond_topo .or. tr_pond_sealvl) then ntrcr = ntrcr + 1 ! refrozen pond ice lid thickness - nt_ipnd = ntrcr ! on level-ice ponds (if frzpnd='hlid') - endif - if (tr_pond_topo) then - ntrcr = ntrcr + 1 ! - nt_ipnd = ntrcr ! refrozen pond ice lid thickness + nt_ipnd = ntrcr ! on ponds (if frzpnd='hlid') endif endif @@ -975,6 +1015,11 @@ subroutine input_data endif endif + if (semi_implicit_Tsfc .and. tr_pond_topo) then + write(nu_diag,*)'ERROR: semi_implicit_Tsfc and tr_pond_topo not supported together' + call icedrv_system_abort(file=__FILE__,line=__LINE__) + endif + !----------------------------------------------------------------- ! set Icepack values !----------------------------------------------------------------- @@ -995,8 +1040,11 @@ subroutine input_data dpscale_in=dpscale, frzpnd_in=frzpnd, & rfracmin_in=rfracmin, rfracmax_in=rfracmax, & pndaspect_in=pndaspect, hs1_in=hs1, hp1_in=hp1, & + apnd_sl_in=apnd_sl, tscale_pnd_drain_in=tscale_pnd_drain, & floediam_in=floediam, hfrazilmin_in=hfrazilmin, & ktherm_in=ktherm, calc_Tsfc_in=calc_Tsfc, & + semi_implicit_Tsfc_in=semi_implicit_Tsfc, & + vapor_flux_correction_in=vapor_flux_correction, & conduct_in=conduct, a_rapid_mode_in=a_rapid_mode, & update_ocn_f_in=update_ocn_f, cpl_frazil_in=cpl_frazil, & Rac_rapid_mode_in=Rac_rapid_mode, & @@ -1016,7 +1064,10 @@ subroutine input_data 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) + windmin_in=windmin, drhosdwind_in=drhosdwind, snwlvlfac_in=snwlvlfac, & + snw_growth_wet_in=snw_growth_wet, drsnw_min_in=drsnw_min, & + snwliq_max_in=snwliq_max, itd_area_min_in=itd_area_min, & + itd_mass_min_in=itd_mass_min) 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) @@ -1025,7 +1076,8 @@ subroutine input_data tr_iso_in=tr_iso, tr_snow_in=tr_snow, & tr_pond_in=tr_pond, & tr_pond_lvl_in=tr_pond_lvl, & - tr_pond_topo_in=tr_pond_topo, tr_fsd_in=tr_fsd) + tr_pond_topo_in=tr_pond_topo, & + tr_pond_sealvl_in=tr_pond_sealvl, tr_fsd_in=tr_fsd) call icepack_init_tracer_indices(nt_Tsfc_in=nt_Tsfc, & nt_sice_in=nt_sice, nt_qice_in=nt_qice, & nt_qsno_in=nt_qsno, nt_iage_in=nt_iage, & @@ -1114,7 +1166,7 @@ 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_lvl, tr_pond_topo, tr_snow + logical (kind=log_kind) :: tr_pond_lvl, tr_pond_topo, tr_pond_sealvl, 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_smice, nt_smliq, nt_rhos, nt_rsnw, & @@ -1131,7 +1183,8 @@ subroutine init_state tr_FY_out=tr_FY, tr_lvl_out=tr_lvl, tr_aero_out=tr_aero, & tr_iso_out=tr_iso, tr_snow_out=tr_snow, & tr_pond_lvl_out=tr_pond_lvl, & - tr_pond_topo_out=tr_pond_topo, tr_fsd_out=tr_fsd) + tr_pond_topo_out=tr_pond_topo, & + tr_pond_sealvl_out=tr_pond_sealvl, tr_fsd_out=tr_fsd) call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, & nt_sice_out=nt_sice, nt_qice_out=nt_qice, & nt_qsno_out=nt_qsno, nt_iage_out=nt_iage, nt_fy_out=nt_fy, & @@ -1182,7 +1235,7 @@ 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_pond_topo) then + if (tr_pond_topo .or. tr_pond_sealvl) then trcr_depend(nt_apnd) = 0 ! melt pond area trcr_depend(nt_hpnd) = 2+nt_apnd ! melt pond depth trcr_depend(nt_ipnd) = 2+nt_apnd ! refrozen pond lid @@ -1246,7 +1299,7 @@ subroutine init_state nt_strata (nt_ipnd,2) = nt_apnd ! on melt pond area nt_strata (nt_ipnd,1) = nt_alvl ! on level ice area endif - if (tr_pond_topo) then + if (tr_pond_topo .or. tr_pond_sealvl) then n_trcr_strata(nt_hpnd) = 1 ! melt pond depth nt_strata (nt_hpnd,1) = nt_apnd ! on melt pond area n_trcr_strata(nt_ipnd) = 1 ! refrozen pond lid @@ -1365,9 +1418,6 @@ subroutine set_state_var (nx, & real (kind=dbl_kind), dimension(nslyr) :: & qsn ! snow enthalpy (J/m3) - 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, 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 @@ -1431,24 +1481,31 @@ subroutine set_state_var (nx, & i = 1 ! ice-free ! already initialized above + if (i <= nx) then ! need to set ocean parameters + sst(i) = sst_init + endif !----------------------------------------------------------------- - i = 2 ! 2-m slab, no snow + i = 2 ! 100% ice concentration slab, thickness and snow from namelist if (i <= nx) then - if (3 <= ncat) then - n = 3 - ainit(n) = c1 ! assumes we are using the default ITD boundaries - hinit(n) = c2 - else - ainit(ncat) = c1 - hinit(ncat) = c2 - endif + sst(i) = sst_init ! initial ocean temperature + do n = 1, ncat + if (hi_init_slab <= hin_max(n)) then + ainit(n) = c1 + hinit(n) = hi_init_slab + exit + endif + enddo + if (hi_init_slab > hin_max(ncat)) then + ainit(ncat) = c1 + hinit(ncat) = hi_init_slab + endif do n = 1, ncat ! ice volume, snow volume aicen(i,n) = ainit(n) vicen(i,n) = hinit(n) * ainit(n) ! m - vsnon(i,n) = c0 + vsnon(i,n) = hsno_init_slab * ainit(n) ! tracers call icepack_init_enthalpy(Tair = Tair(i), & Tf = Tf(i), & @@ -1492,8 +1549,9 @@ subroutine set_state_var (nx, & i = 3 ! full thickness distribution if (i <= nx) then + sst(i) = sst_init ! initial category areas in cells with ice - hbar = c3 ! initial ice thickness with greatest area + hbar = hbar_init_itd ! initial ice thickness with greatest area ! Note: the resulting average ice thickness ! tends to be less than hbar due to the ! nonlinear distribution of ice thicknesses @@ -1517,7 +1575,7 @@ subroutine set_state_var (nx, & ! ice volume, snow volume aicen(i,n) = ainit(n) vicen(i,n) = hinit(n) * ainit(n) ! m - vsnon(i,n) = min(aicen(i,n)*hsno_init,p2*vicen(i,n)) + vsnon(i,n) = min(aicen(i,n)*hsno_init_itd,p2*vicen(i,n)) ! tracers call icepack_init_enthalpy(Tair = Tair(i), & Tf = Tf(i), & diff --git a/configuration/driver/icedrv_init_column.F90 b/configuration/driver/icedrv_init_column.F90 index ce1d1bbd..87d0b9da 100644 --- a/configuration/driver/icedrv_init_column.F90 +++ b/configuration/driver/icedrv_init_column.F90 @@ -610,16 +610,21 @@ subroutine init_zbgc tr_bgc_hum, tr_aero logical (kind=log_kind) :: & - solve_zsal, skl_bgc, z_tracers, scale_bgc, solve_zbgc, dEdd_algae, & + skl_bgc, z_tracers, scale_bgc, solve_zbgc, dEdd_algae, & modal_aero, restore_bgc + logical (kind=log_kind) :: & + solve_zsal = .false. ! deprecated with zsalinity + character (char_len) :: & bgc_flux_type + real (kind=dbl_kind) :: & + grid_oS, l_skS ! deprecated with zsalinity + real (kind=dbl_kind) :: & grid_o, grid_o_t, l_sk, initbio_frac, & - frazil_scav, grid_oS, l_skS, & - phi_snow, & + frazil_scav, phi_snow, & ratio_Si2N_diatoms , ratio_Si2N_sp , ratio_Si2N_phaeo , & ratio_S2N_diatoms , ratio_S2N_sp , ratio_S2N_phaeo , & ratio_Fe2C_diatoms , ratio_Fe2C_sp , ratio_Fe2C_phaeo , & @@ -827,7 +832,7 @@ subroutine init_zbgc dEdd_algae_out=dEdd_algae, solve_zbgc_out=solve_zbgc, grid_o_t_out=grid_o_t, & bgc_flux_type_out=bgc_flux_type, grid_o_out=grid_o, l_sk_out=l_sk, & initbio_frac_out=initbio_frac, frazil_scav_out=frazil_scav, & - grid_oS_out=grid_oS, l_skS_out=l_skS, phi_snow_out=phi_snow, & + phi_snow_out=phi_snow, & algal_vel_out=algal_vel, R_dFe2dust_out=R_dFe2dust, & dustFe_sol_out=dustFe_sol, T_max_out=T_max, fsal_out=fsal, & op_dep_min_out=op_dep_min, fr_graze_s_out=fr_graze_s, & @@ -835,7 +840,7 @@ subroutine init_zbgc fr_dFe_out=fr_dFe, k_nitrif_out=k_nitrif, t_iron_conv_out=t_iron_conv, & max_loss_out=max_loss, max_dfe_doc1_out=max_dfe_doc1, fr_resp_out=fr_resp, & fr_resp_s_out=fr_resp_s, y_sk_DMS_out=y_sk_DMS, t_sk_conv_out=t_sk_conv, & - t_sk_ox_out=t_sk_ox, modal_aero_out=modal_aero, solve_zsal_out = solve_zsal) + t_sk_ox_out=t_sk_ox, modal_aero_out=modal_aero) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__, line=__LINE__) @@ -1178,7 +1183,7 @@ subroutine init_zbgc dEdd_algae_in=dEdd_algae, solve_zbgc_in=solve_zbgc, grid_o_t_in=grid_o_t, & bgc_flux_type_in=bgc_flux_type, grid_o_in=grid_o, l_sk_in=l_sk, & initbio_frac_in=initbio_frac, frazil_scav_in=frazil_scav, & - grid_oS_in=grid_oS, l_skS_in=l_skS, phi_snow_in=phi_snow, & + phi_snow_in=phi_snow, & algal_vel_in=algal_vel, R_dFe2dust_in=R_dFe2dust, & dustFe_sol_in=dustFe_sol, T_max_in=T_max, fsal_in=fsal, & op_dep_min_in=op_dep_min, fr_graze_s_in=fr_graze_s, & @@ -1186,7 +1191,7 @@ subroutine init_zbgc fr_dFe_in=fr_dFe, k_nitrif_in=k_nitrif, t_iron_conv_in=t_iron_conv, & max_loss_in=max_loss, max_dfe_doc1_in=max_dfe_doc1, fr_resp_in=fr_resp, & fr_resp_s_in=fr_resp_s, y_sk_DMS_in=y_sk_DMS, t_sk_conv_in=t_sk_conv, & - t_sk_ox_in=t_sk_ox, modal_aero_in=modal_aero, solve_zsal_in = solve_zsal) + t_sk_ox_in=t_sk_ox, modal_aero_in=modal_aero) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & file=__FILE__, line=__LINE__) diff --git a/configuration/driver/icedrv_restart.F90 b/configuration/driver/icedrv_restart.F90 index c9b07667..250c4b1b 100644 --- a/configuration/driver/icedrv_restart.F90 +++ b/configuration/driver/icedrv_restart.F90 @@ -89,7 +89,7 @@ subroutine dumpfile logical (kind=log_kind) :: & tr_iage, tr_FY, tr_lvl, tr_iso, tr_aero, tr_brine, & - tr_pond_topo, tr_pond_lvl, tr_snow, tr_fsd + tr_pond_topo, tr_pond_lvl, tr_pond_sealvl, tr_snow, tr_fsd ! skl_bgc, z_tracers integer (kind=int_kind) :: dims(2) @@ -117,7 +117,9 @@ 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_lvl_out=tr_pond_lvl,tr_snow_out=tr_snow,tr_fsd_out=tr_fsd) + tr_pond_lvl_out=tr_pond_lvl, & + tr_pond_sealvl_out=tr_pond_sealvl, & + tr_snow_out=tr_snow,tr_fsd_out=tr_fsd) ! call icepack_query_parameters(skl_bgc_out=skl_bgc, z_tracers_out=z_tracers) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & @@ -219,6 +221,7 @@ subroutine dumpfile if (tr_lvl) call write_restart_lvl(dims) ! level ice tracer if (tr_pond_lvl) call write_restart_pond_lvl(dims) ! level-ice melt ponds if (tr_pond_topo) call write_restart_pond_topo(dims) ! topographic melt ponds + if (tr_pond_sealvl) call write_restart_pond_sealvl(dims) ! same restart fields as lvl if (tr_snow) call write_restart_snow(dims) ! snow metamorphosis tracers if (tr_iso) call write_restart_iso(dims) ! ice isotopes if (tr_aero) call write_restart_aero(dims) ! ice aerosols @@ -277,7 +280,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_lvl, tr_snow, tr_fsd + tr_pond_topo, tr_pond_lvl, tr_pond_sealvl, tr_snow, tr_fsd character(len=char_len_long) :: filename character(len=*), parameter :: subname='(restartfile)' @@ -294,7 +297,9 @@ 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_lvl_out=tr_pond_lvl,tr_snow_out=tr_snow,tr_fsd_out=tr_fsd) + tr_pond_lvl_out=tr_pond_lvl, & + tr_pond_sealvl_out=tr_pond_sealvl, & + 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__) @@ -395,6 +400,7 @@ subroutine restartfile (ice_ic) if (tr_FY) call read_restart_FY() ! first-year area tracer if (tr_lvl) call read_restart_lvl() ! level ice tracer if (tr_pond_lvl) call read_restart_pond_lvl() ! level-ice melt ponds + if (tr_pond_sealvl) call read_restart_pond_sealvl() ! sealvl ponds same as lvl 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 @@ -996,6 +1002,68 @@ end subroutine read_restart_pond_lvl !======================================================================= +! Dumps all values needed for restarting +! + subroutine write_restart_pond_sealvl(dims) + + use icedrv_arrays_column, only: dhsn, ffracn + use icedrv_flux, only: fsnow + use icedrv_state, only: trcrn + use icedrv_domain_size, only: ncat + + integer (kind=int_kind), intent(in), optional :: & + dims(:) ! netcdf dimension IDs + + integer (kind=int_kind) :: nt_apnd, nt_hpnd, nt_ipnd + character(len=*), parameter :: subname='(write_restart_pond_sealvl)' + + call icepack_query_tracer_indices(nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, & + nt_ipnd_out=nt_ipnd) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & + file=__FILE__,line= __LINE__) + + call write_restart_field(nu_dump,trcrn(:,nt_apnd,:),ncat,'apnd',dims) + call write_restart_field(nu_dump,trcrn(:,nt_hpnd,:),ncat,'hpnd',dims) + call write_restart_field(nu_dump,trcrn(:,nt_ipnd,:),ncat,'ipnd',dims) + call write_restart_field(nu_dump,fsnow(:),1,'fsnow',dims) + call write_restart_field(nu_dump,dhsn(:,:),ncat,'dhsn',dims) + call write_restart_field(nu_dump,ffracn(:,:),ncat,'ffracn',dims) + + end subroutine write_restart_pond_sealvl + +!======================================================================= + +! Reads all values needed for a sea level pond restart +! + subroutine read_restart_pond_sealvl() + + use icedrv_arrays_column, only: dhsn, ffracn + use icedrv_flux, only: fsnow + use icedrv_state, only: trcrn + use icedrv_domain_size, only: ncat + integer (kind=int_kind) :: nt_apnd, nt_hpnd, nt_ipnd + character(len=*), parameter :: subname='(write_restart_pond_sealvl)' + + call icepack_query_tracer_indices(nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, & + nt_ipnd_out=nt_ipnd) + 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 level-ice ponds' + + call read_restart_field(nu_restart,trcrn(:,nt_apnd,:),ncat,'apnd') + call read_restart_field(nu_restart,trcrn(:,nt_hpnd,:),ncat,'hpnd') + call read_restart_field(nu_restart,trcrn(:,nt_ipnd,:),ncat,'ipnd') + call read_restart_field(nu_restart,fsnow(:),1,'fsnow') + call read_restart_field(nu_restart,dhsn(:,:),ncat,'dhsn') + call read_restart_field(nu_restart,ffracn(:,:),ncat,'ffracn') + + end subroutine read_restart_pond_sealvl + +!======================================================================= + ! Dumps all values needed for restarting ! ! authors Elizabeth Hunke, LANL diff --git a/configuration/driver/icedrv_step.F90 b/configuration/driver/icedrv_step.F90 index 011cda9d..f43d5a78 100644 --- a/configuration/driver/icedrv_step.F90 +++ b/configuration/driver/icedrv_step.F90 @@ -129,6 +129,8 @@ subroutine step_therm1 (dt) 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_flux, only: dpnd_flushn, dpnd_exponn, dpnd_freebdn, dpnd_initialn, dpnd_dlidn + use icedrv_flux, only: dpnd_flush, dpnd_expon, dpnd_freebd, dpnd_initial, dpnd_dlid use icedrv_init, only: lmask_n, lmask_s use icedrv_state, only: aice, aicen, aice_init, aicen_init, vicen_init use icedrv_state, only: vice, vicen, vsno, vsnon, trcrn, uvel, vvel, vsnon_init @@ -373,7 +375,12 @@ subroutine step_therm1 (dt) afsdn = trcrn (i,nt_fsd:nt_fsd+nfsd-1,:), & 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) + yday = yday, prescribed_ice = prescribed_ice, & + dpnd_flush = dpnd_flush(i), dpnd_flushn = dpnd_flushn(i,:), & + dpnd_expon = dpnd_expon(i), dpnd_exponn = dpnd_exponn(i,:), & + dpnd_freebd = dpnd_freebd(i), dpnd_freebdn = dpnd_freebdn(i,:), & + dpnd_initial= dpnd_initial(i), dpnd_initialn= dpnd_initialn(i,:), & + dpnd_dlid = dpnd_dlid(i), dpnd_dlidn = dpnd_dlidn(i,:)) if (tr_aero) then do n = 1, ncat @@ -439,6 +446,7 @@ subroutine step_therm2 (dt) use icedrv_flux, only: fsalt, Tf, sss, salinz, fhocn, rsiden, wlat use icedrv_flux, only: meltl, frazil_diag, flux_bio, faero_ocn, fiso_ocn use icedrv_flux, only: HDO_ocn, H2_16O_ocn, H2_18O_ocn + use icedrv_flux, only: dpnd_melt use icedrv_init, only: tmask use icedrv_state, only: aice, aicen, aice0, trcr_depend use icedrv_state, only: aicen_init, vicen_init, trcrn, vicen, vsnon @@ -460,9 +468,9 @@ subroutine step_therm2 (dt) logical (kind=log_kind) :: & tr_fsd ! floe size distribution tracers - + character (len=char_len) :: & - wave_height_type + wave_height_type ! type of significant wave height forcing character(len=*), parameter :: subname='(step_therm2)' @@ -482,12 +490,11 @@ subroutine step_therm2 (dt) do i = 1, nx if (tmask(i)) then - ! wave_sig_ht - compute here to pass to add new ice - if (tr_fsd .and. trim(wave_height_type) == 'internal') then - wave_sig_ht(i) = c4*SQRT(SUM(wave_spectrum(i,:)*dwavefreq(:))) - !else - ! wave_sig_ht(i) provided by coupler or external data. - endif + ! significant wave height + if (tr_fsd .and. trim(wave_height_type) == 'internal') then + wave_sig_ht(i) = c4*SQRT(SUM(wave_spectrum(i,:)*dwavefreq(:))) + ! else wave_sig_ht = 0 unless provided by coupler or other external data + endif call icepack_step_therm2(dt=dt, & hin_max=hin_max(:), & @@ -525,11 +532,11 @@ subroutine step_therm2 (dt) wave_sig_ht=wave_sig_ht(i), & wave_spectrum=wave_spectrum(i,:), & wavefreq=wavefreq(:), & - dwavefreq=dwavefreq(:), & d_afsd_latg=d_afsd_latg(i,:), & d_afsd_newi=d_afsd_newi(i,:), & d_afsd_latm=d_afsd_latm(i,:), & - d_afsd_weld=d_afsd_weld(i,:)) + d_afsd_weld=d_afsd_weld(i,:), & + dpnd_melt=dpnd_melt(i)) endif ! tmask @@ -674,21 +681,11 @@ subroutine step_dyn_wave (dt) ntrcr, & ! nbtrcr ! - character (len=char_len) :: & - wave_spec_type , & - wave_height_type - character(len=*), parameter :: subname = '(step_dyn_wave)' - call icepack_query_parameters(wave_spec_type_out=wave_spec_type, wave_height_type_out=wave_height_type) - call icepack_warnings_flush(nu_diag) - if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, & - file=__FILE__,line= __LINE__) - do i = 1, nx d_afsd_wave(i,:) = c0 - call icepack_step_wavefracture (wave_spec_type=wave_spec_type, & - wave_height_type=wave_height_type, & + call icepack_step_wavefracture ( & dt=dt, nfreq=nfreq, & aice = aice (i), & vice = vice (i), & @@ -697,7 +694,8 @@ subroutine step_dyn_wave (dt) wavefreq = wavefreq (:), & dwavefreq = dwavefreq (:), & trcrn = trcrn (i,:,:), & - d_afsd_wave = d_afsd_wave (i,:)) + d_afsd_wave = d_afsd_wave (i,:), & + wave_height = wave_sig_ht (i)) end do ! i call icepack_warnings_flush(nu_diag) @@ -825,6 +823,7 @@ subroutine step_dyn_ridge (dt, ndtd) use icedrv_flux, only: dvirdgdt, opening, closing, fpond, fresh, fhocn use icedrv_flux, only: aparticn, krdgn, aredistn, vredistn, dardg1ndt, dardg2ndt use icedrv_flux, only: dvirdgndt, araftn, vraftn, fsalt, flux_bio, faero_ocn, fiso_ocn + use icedrv_flux, only: dpnd_ridge use icedrv_init, only: tmask use icedrv_state, only: trcrn, vsnon, aicen, vicen use icedrv_state, only: aice, aice0, trcr_depend, n_trcr_strata @@ -895,7 +894,8 @@ subroutine step_dyn_ridge (dt, ndtd) aice=aice(i), fsalt=fsalt(i), & first_ice=first_ice(i,:), & flux_bio=flux_bio(i,1:nbtrcr), & - closing=closing(i), Tf=Tf(i) ) + closing=closing(i), Tf=Tf(i), & + dpnd_ridge=dpnd_ridge(i)) endif ! tmask @@ -934,7 +934,8 @@ subroutine step_dyn_ridge (dt, ndtd) araftn=araftn(i,:), vraftn=vraftn(i,:), & aice=aice(i), fsalt=fsalt(i), & first_ice=first_ice(i,:), & - flux_bio=flux_bio(i,1:nbtrcr), Tf = Tf(i)) + flux_bio=flux_bio(i,1:nbtrcr), Tf = Tf(i), & + dpnd_ridge=dpnd_ridge(i)) endif ! tmask diff --git a/configuration/scripts/icepack.batch.csh b/configuration/scripts/icepack.batch.csh index 8a077969..3dec1584 100755 --- a/configuration/scripts/icepack.batch.csh +++ b/configuration/scripts/icepack.batch.csh @@ -64,6 +64,31 @@ cat >> ${jobfile} << EOFB ###PBS -m be EOFB +else if (${ICE_MACHINE} =~ gadi*) then +if (${ICE_MACHINE_QUEUE} =~ *sr) then #sapphire rapids + @ memuse = ( $ncores * 481 / 100 ) +else if (${ICE_MACHINE_QUEUE} =~ *bw) then #broadwell + @ memuse = ( $ncores * 457 / 100 ) +else if (${ICE_MACHINE_QUEUE} =~ *sl) then + @ memuse = ( $ncores * 6 ) +else #normal queues + @ memuse = ( $ncores * 395 / 100 ) +endif +cat >> ${jobfile} << EOFB +#PBS -q ${ICE_MACHINE_QUEUE} +#PBS -P ${ICE_MACHINE_PROJ} +#PBS -N ${ICE_CASENAME} +#PBS -l storage=gdata/${ICE_MACHINE_PROJ}+scratch/${ICE_MACHINE_PROJ}+gdata/ik11 +#PBS -l ncpus=${ncores} +#PBS -l mem=${memuse}gb +#PBS -l walltime=${ICE_RUNLENGTH} +#PBS -j oe +#PBS -W umask=003 +#PBS -o ${ICE_CASEDIR} +source /etc/profile.d/modules.csh +module use `echo ${MODULEPATH} | sed 's/:/ /g'` #copy the users modules +EOFB + else if (${ICE_MACHINE} =~ casper*) then cat >> ${jobfile} << EOFB #PBS -q ${ICE_MACHINE_QUEUE} diff --git a/configuration/scripts/icepack_in b/configuration/scripts/icepack_in index 9e83842a..0ea12627 100644 --- a/configuration/scripts/icepack_in +++ b/configuration/scripts/icepack_in @@ -7,6 +7,11 @@ npt = 8760 ndtd = 1 ice_ic = 'default' + hi_init_slab = 2.0 + hsno_init_slab = 0.0 + hbar_init_itd = 3.0 + hsno_init_itd = 0.25 + sst_init = -1.8 restart = .false. restart_dir = './restart/' restart_format = 'bin' @@ -17,6 +22,8 @@ history_format = 'none' cpl_bgc = .false. conserv_check = .false. + itd_area_min = 1.e-11 + itd_mass_min = 1.e-10 / &grid_nml @@ -29,6 +36,7 @@ tr_lvl = .true. tr_pond_topo = .false. tr_pond_lvl = .true. + tr_pond_sealvl = .false. tr_snow = .false. tr_aero = .false. tr_fsd = .false. @@ -50,6 +58,7 @@ Tliquidus_max = -0.1d0 floediam = 300.0d0 hfrazilmin = 0.05d0 + tscale_pnd_drain = 10.0d0 / &shortwave_nml @@ -58,7 +67,7 @@ albicev = 0.78 albicei = 0.36 albsnowv = 0.98 - albsnowi = 0.70 + albsnowi = 0.70 ahmax = 0.3 R_ice = 0. R_pnd = 0. @@ -81,6 +90,7 @@ rfracmin = 0.15 rfracmax = 1. pndaspect = 0.8 + apnd_sl = 0.27d0 / &snow_nml @@ -96,6 +106,9 @@ drhosdwind = 27.3 snwlvlfac = 0.3 snw_aging_table = 'test' + snw_growth_wet = 4.22e5 + drsnw_min = 0.0 + snwliq_max = 0.033 / &forcing_nml @@ -122,6 +135,9 @@ wave_height_type= 'none' restore_ocn = .false. trestore = 90 + sss_fixed = 34.0 + qdp_fixed = 0.0 + hmix_fixed = 20.0 precip_units = 'mks' default_season = 'spring' atm_data_type = 'clim' @@ -138,6 +154,9 @@ atm_data_format = 'bin' ocn_data_format = 'bin' bgc_data_format = 'bin' + precalc_forc = .false. + semi_implicit_Tsfc = .false. + vapor_flux_correction = .false. / &dynamics_nml @@ -158,7 +177,6 @@ solve_zbgc = .false. bgc_flux_type = 'Jin2006' scale_bgc = .false. - solve_zsal = .false. tr_bgc_Nit = .false. tr_bgc_C = .false. tr_bgc_chl = .false. @@ -168,25 +186,23 @@ tr_bgc_PON = .false. tr_bgc_hum = .false. tr_bgc_DON = .false. - tr_bgc_Fe = .false. + tr_bgc_Fe = .false. grid_o = 0.006 grid_o_t = 0.006 l_sk = 2.0 - grid_oS = 0.0 - l_skS = 0.028 phi_snow = -1.0 initbio_frac = 1.0 - frazil_scav = 0.8 - ratio_Si2N_diatoms = 1.8 + frazil_scav = 0.8 + ratio_Si2N_diatoms = 1.8 ratio_Si2N_sp = 0.0 ratio_Si2N_phaeo = 0.0 - ratio_S2N_diatoms = 0.03 - ratio_S2N_sp = 0.03 + ratio_S2N_diatoms = 0.03 + ratio_S2N_sp = 0.03 ratio_S2N_phaeo = 0.03 ratio_Fe2C_diatoms = 0.0033 ratio_Fe2C_sp = 0.0033 ratio_Fe2C_phaeo = 0.1 - ratio_Fe2N_diatoms = 0.023 + ratio_Fe2N_diatoms = 0.023 ratio_Fe2N_sp = 0.023 ratio_Fe2N_phaeo = 0.7 ratio_Fe2DON = 0.023 diff --git a/configuration/scripts/machines/Macros.derecho_gnu b/configuration/scripts/machines/Macros.derecho_gnu index 103ff8cd..0ad50a67 100644 --- a/configuration/scripts/machines/Macros.derecho_gnu +++ b/configuration/scripts/machines/Macros.derecho_gnu @@ -11,10 +11,19 @@ FREEFLAGS := -ffree-form FFLAGS := -fconvert=big-endian -fbacktrace -ffree-line-length-none -fallow-argument-mismatch FFLAGS_NOOPT:= -O0 +ifeq ($(ICE_COVERAGE), true) + FFLAGS += -O0 -g -fprofile-arcs -ftest-coverage + CFLAGS += -O0 -g -coverage + LDFLAGS += -g -ftest-coverage -fprofile-arcs +else ifeq ($(ICE_BLDDEBUG), true) FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=invalid,zero,overflow --std f2008 # FFLAGS += -O0 -g -fcheck=all -finit-real=snan -fimplicit-none -ffpe-trap=invalid,zero,overflow CFLAGS += -O0 +else + FFLAGS += -O2 + CFLAGS += -O2 +endif endif SCC := gcc diff --git a/configuration/scripts/machines/Macros.gadi_intel b/configuration/scripts/machines/Macros.gadi_intel new file mode 100644 index 00000000..13593fc7 --- /dev/null +++ b/configuration/scripts/machines/Macros.gadi_intel @@ -0,0 +1,50 @@ +#============================================================================== +# Makefile macros for NCI Gadi, intel compiler +#============================================================================== + +CPP := fpp +CPPDEFS := -DFORTRANUNDERSCORE -DREPRODUCIBLE ${ICE_CPPDEFS} +CFLAGS := -c -O2 -fp-model precise -Wno-unused-variable -Wno-unused-parameter + +FIXEDFLAGS := -132 +FREEFLAGS := -FR + +NCI_INTEL_FLAGS := -r8 -i4 -traceback -w -fpe0 -ftz -convert big_endian -assume byterecl -check noarg_temp_created +NCI_REPRO_FLAGS := -fp-model precise -fp-model source -align all + +ifeq ($(ICE_BLDDEBUG), true) + NCI_DEBUG_FLAGS := -g3 -O0 -debug all -check all -no-vec -assume nobuffered_io + FFLAGS := $(NCI_INTEL_FLAGS) $(NCI_REPRO_FLAGS) $(NCI_DEBUG_FLAGS) + CPPDEFS := $(CPPDEFS) -DDEBUG=$(DEBUG) +else + NCI_OPTIM_FLAGS := -g3 -O2 -axCORE-AVX2 -debug all -check none -qopt-report=5 -qopt-report-annotate -assume buffered_io + FFLAGS := $(NCI_INTEL_FLAGS) $(NCI_REPRO_FLAGS) $(NCI_OPTIM_FLAGS) +endif + +SCC := icx +SFC := ifort +MPICC := mpicc +MPIFC := mpifort + +ifeq ($(ICE_COMMDIR), mpi) + FC := $(MPIFC) + CC := $(MPICC) +else + FC := $(SFC) + CC := $(SCC) +endif +LD:= $(FC) + +SLIBS := $(SLIBS) +INCLDIR := $(INCLDIR) + +# if spack modules loaded, use them. otherwise use system modules +ifndef SPACK_NETCDF_FORTRAN_ROOT + SLIBS += -L$(NETCDF)/lib -lnetcdf -lnetcdff + INCLDIR += -I$(NETCDF)/include +else + SLIBS += -L$(SPACK_NETCDF_C_ROOT)/lib64 -lnetcdf + SLIBS += -L$(SPACK_NETCDF_FORTRAN_ROOT)/lib -lnetcdff + INCLDIR += -I$(SPACK_NETCDF_C_ROOT)/include + INCLDIR += -I$(SPACK_NETCDF_FORTRAN_ROOT)/include +endif diff --git a/configuration/scripts/machines/env.derecho_gnu b/configuration/scripts/machines/env.derecho_gnu index 0b5121c1..791b5796 100644 --- a/configuration/scripts/machines/env.derecho_gnu +++ b/configuration/scripts/machines/env.derecho_gnu @@ -10,14 +10,15 @@ if ("$inp" != "-nomodules") then source ${MODULESHOME}/init/csh module --force purge -module load ncarenv/23.06 +module load ncarenv/24.12 module load craype -module load gcc/12.2.0 +module load gcc/12.4.0 module load ncarcompilers #module load cray-mpich/8.1.25 #module load hdf5/1.12.2 module load netcdf/4.9.2 -module load cray-libsci/23.02.1.1 +module load cray-libsci/24.03.0 +module load lcov # For perftools with mpiexec # module load perftools-base @@ -38,7 +39,7 @@ setenv OMP_STACKSIZE 64M setenv ICE_MACHINE_MACHNAME derecho setenv ICE_MACHINE_MACHINFO "HPE Cray EX Milan Slingshot 11" setenv ICE_MACHINE_ENVNAME gnu -setenv ICE_MACHINE_ENVINFO "gcc 12.2.0 20220819, netcdf4.9.2" +setenv ICE_MACHINE_ENVINFO "gcc 12.4.0, netcdf4.9.2" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR /glade/derecho/scratch/$user/ICEPACK_RUNS setenv ICE_MACHINE_INPUTDATA /glade/campaign/cesm/development/pcwg @@ -49,3 +50,23 @@ setenv ICE_MACHINE_QUEUE "develop" setenv ICE_MACHINE_TPNODE 128 setenv ICE_MACHINE_BLDTHRDS 1 setenv ICE_MACHINE_QSTAT "qstat " + +# For lcov +#set lcovpath = "/glade/u/home/tcraig/bin" +#set lcovp5l = "/glade/u/home/tcraig/usr/lib/perl5/site_perl/5.18.2/x86_64-linux-thread-multi" + +#if ($?PATH) then +# if ("$PATH" !~ "*${lcovpath}*") then +# setenv PATH ${PATH}:$lcovpath +# endif +#else +# setenv PATH $lcovpath +#endif + +#if ($?PERL5LIB) then +# if ("$PERL5LIB" !~ "*${lcovp5l}*") then +# setenv PERL5LIB ${PERL5LIB}:$lcovp5l +# endif +#else +# setenv PERL5LIB $lcovp5l +#endif diff --git a/configuration/scripts/machines/env.discover_intel b/configuration/scripts/machines/env.discover_intel index 4f13d1a5..b8bdec18 100755 --- a/configuration/scripts/machines/env.discover_intel +++ b/configuration/scripts/machines/env.discover_intel @@ -47,7 +47,7 @@ setenv ICE_MACHINE_WKDIR /discover/nobackup/$user/ICEPACK_RUNS setenv ICE_MACHINE_INPUTDATA /discover/nobackup/sakella/icepack_data setenv ICE_MACHINE_BASELINE /discover/nobackup/$user/ICEPACK_BASELINE setenv ICE_MACHINE_SUBMIT "sbatch" -setenv ICE_MACHINE_ACCT g0613 +setenv ICE_MACHINE_ACCT g0609 setenv ICE_MACHINE_QUEUE "share" setenv ICE_MACHINE_TPNODE 36 setenv ICE_MACHINE_BLDTHRDS 1 diff --git a/configuration/scripts/machines/env.gadi_intel b/configuration/scripts/machines/env.gadi_intel new file mode 100644 index 00000000..59a70949 --- /dev/null +++ b/configuration/scripts/machines/env.gadi_intel @@ -0,0 +1,32 @@ +#!/bin/csh -f + +set inp = "undefined" +if ($#argv == 1) then + set inp = $1 +endif + +if ("$inp" != "-nomodules") then + + source /etc/profile.d/modules.csh + + module load intel-compiler + module load netcdf + +endif + +setenv ICE_MACHINE_MACHNAME gadi +setenv ICE_MACHINE_MACHINFO "Intel Xeon Scalable" +setenv ICE_MACHINE_ENVNAME intel +setenv ICE_MACHINE_ENVINFO INTEL_COMPILER_VERSION=$INTEL_COMPILER_VERSION +setenv ICE_MACHINE_MAKE gmake +setenv ICE_MACHINE_WKDIR /scratch/$PROJECT/$USER/ICEPACK_RUNS +setenv ICE_MACHINE_INPUTDATA /g/data/ik11/inputs/CICE_data/icepack-dirs/input +setenv ICE_MACHINE_BASELINE /scratch/$PROJECT/$USER/ICEPACK_BASELINE +setenv ICE_MACHINE_SUBMIT "qsub" +setenv ICE_MACHINE_PROJ $PROJECT +setenv ICE_MACHINE_ACCT $USER +setenv ICE_MACHINE_QUEUE "normal" +setenv ICE_MACHINE_TPNODE 48 +setenv ICE_MACHINE_BLDTHRDS 4 +setenv ICE_MACHINE_QSTAT "qstat" +setenv ICE_CPPDEFS -DUSE_NETCDF \ No newline at end of file diff --git a/configuration/scripts/machines/env.perlmutter_cray b/configuration/scripts/machines/env.perlmutter_cray index 6cafd015..8f20da6b 100644 --- a/configuration/scripts/machines/env.perlmutter_cray +++ b/configuration/scripts/machines/env.perlmutter_cray @@ -18,13 +18,13 @@ source ${MODULESHOME}/init/csh #module load cpe/23.03 #module unload gpu module load cpu -module load PrgEnv-cray +module load PrgEnv-cray/8.5.0 module unload cce -module load cce/15.0.1 +module load cce/17.0.0 module unload cray-netcdf module unload cray-hdf5 -module load cray-hdf5/1.12.2.3 -module load cray-netcdf/4.9.0.3 +module load cray-hdf5/1.12.2.9 +module load cray-netcdf/4.9.0.9 #module unload cray-pals #module load cray-pals/1.2.2 @@ -37,7 +37,7 @@ setenv PALS_QUIET TRUE setenv ICE_MACHINE_MACHNAME perlmutter setenv ICE_MACHINE_MACHINFO "HPE Cray EX AMD EPYC 7763 Milan, Slingshot-11 Interconnect" setenv ICE_MACHINE_ENVNAME cray -setenv ICE_MACHINE_ENVINFO "Cray clang/Fortran 15.0.1, netcdf4.9.0.3" +setenv ICE_MACHINE_ENVINFO "Cray clang/Fortran 17.0.0, netcdf4.9.0.9" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $SCRATCH/ICEPACK_RUNS setenv ICE_MACHINE_INPUTDATA /global/cfs/cdirs/e3sm/tcraig/cice-consortium diff --git a/configuration/scripts/machines/env.perlmutter_gnu b/configuration/scripts/machines/env.perlmutter_gnu index 417cdc89..5969a400 100644 --- a/configuration/scripts/machines/env.perlmutter_gnu +++ b/configuration/scripts/machines/env.perlmutter_gnu @@ -18,13 +18,13 @@ source ${MODULESHOME}/init/csh #module load cpe/23.03 #module unload gpu module load cpu -module load PrgEnv-gnu +module load PrgEnv-gnu/8.5.0 module unload gcc -module load gcc/11.2.0 +module load gcc-native/12.3 module unload cray-netcdf module unload cray-hdf5 -module load cray-hdf5/1.12.2.3 -module load cray-netcdf/4.9.0.3 +module load cray-hdf5/1.12.2.9 +module load cray-netcdf/4.9.0.9 #module unload cray-pals #module load cray-pals/1.2.2 diff --git a/configuration/scripts/machines/env.perlmutter_intel b/configuration/scripts/machines/env.perlmutter_intel index 85b6989a..12a03660 100644 --- a/configuration/scripts/machines/env.perlmutter_intel +++ b/configuration/scripts/machines/env.perlmutter_intel @@ -18,13 +18,13 @@ source ${MODULESHOME}/init/csh #module load cpe/23.03 #module unload gpu module load cpu -module load PrgEnv-intel +module load PrgEnv-intel/8.5.0 module unload intel -module load intel/2023.1.0 +module load intel/2023.2.0 module unload cray-netcdf module unload cray-hdf5 -module load cray-hdf5/1.12.2.3 -module load cray-netcdf/4.9.0.3 +module load cray-hdf5/1.12.2.9 +module load cray-netcdf/4.9.0.9 #module unload cray-pals #module load cray-pals/1.2.2 @@ -37,7 +37,7 @@ setenv PALS_QUIET TRUE setenv ICE_MACHINE_MACHNAME perlmutter setenv ICE_MACHINE_MACHINFO "HPE Cray EX AMD EPYC 7763 Milan, Slingshot-11 Interconnect" setenv ICE_MACHINE_ENVNAME intel -setenv ICE_MACHINE_ENVINFO "ifort 2021.9.0 20230302, netcdf4.9.0.3" +setenv ICE_MACHINE_ENVINFO "ifort 2021.10.0 20230609, netcdf4.9.0.9" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $SCRATCH/ICEPACK_RUNS setenv ICE_MACHINE_INPUTDATA /global/cfs/cdirs/e3sm/tcraig/cice-consortium diff --git a/configuration/scripts/options/set_nml.atmmosaic b/configuration/scripts/options/set_nml.atmmosaic new file mode 100644 index 00000000..ec7dab91 --- /dev/null +++ b/configuration/scripts/options/set_nml.atmmosaic @@ -0,0 +1,17 @@ +atm_data_type = 'MDF' +atm_data_file = 'MOSAiC_atm_drift1_precip_MDF_20191015_20200731.nc' +atm_data_format = 'nc' +use_leap_years = .true. +fyear_init = 2019 +year_init = 2019 +istep0 = 7728 +npt = 6132 +precalc_forc = .true. +hi_init_slab = 0.55 +hsno_init_slab = 0.07 +hbar_init_itd = 1.5 +hsno_init_itd = 0.15 +qdp_fixed = -1.0 +sst_init = -1.8 +sss_fixed = 32.0 +hmix_fixed = 45.0 diff --git a/configuration/scripts/options/set_nml.ocnmosaic b/configuration/scripts/options/set_nml.ocnmosaic new file mode 100644 index 00000000..6334faf1 --- /dev/null +++ b/configuration/scripts/options/set_nml.ocnmosaic @@ -0,0 +1,6 @@ +ocn_data_type = 'MDF' +ocn_data_file = 'MOSAiC_ocn_drift1_MDF_20191006_20200731.nc' +ocn_data_format = 'nc' +ustar_min = 0.005 +precalc_forc = .true. +ice_data_file = 'unknown_ice_data_file' diff --git a/configuration/scripts/options/set_nml.pondsealvl b/configuration/scripts/options/set_nml.pondsealvl new file mode 100644 index 00000000..17c2511a --- /dev/null +++ b/configuration/scripts/options/set_nml.pondsealvl @@ -0,0 +1,7 @@ +apnd_sl = 0.27d0 +rfracmin = 1.0d0 +rfracmax = 1.0d0 +tr_pond_topo = .false. +tr_pond_lvl = .false. +tr_pond_sealvl = .true. +tscale_pnd_drain = 0.5d0 diff --git a/configuration/scripts/set_version_number.csh b/configuration/scripts/set_version_number.csh index 3c727433..a31cb2ec 100755 --- a/configuration/scripts/set_version_number.csh +++ b/configuration/scripts/set_version_number.csh @@ -10,6 +10,7 @@ if ( $#argv > 1 ) then endif set versno = $1 +set cdate = `date +%Y-%m-%d` #echo "$0 versno = $versno" cp -f doc/source/conf.py doc/source/conf.py.bu @@ -17,6 +18,12 @@ cp -f doc/source/conf.py doc/source/conf.py.bu sed -i 's|^.*version.*=.*$|version = u'"'"${versno}"'"' | g' doc/source/conf.py sed -i 's|^.*release.*=.*$|version = u'"'"${versno}"'"' | g' doc/source/conf.py +cp -f .zenodo.json .zenodo.json.bu + +sed -i 's|^\(.*CICE-Consortium/Icepack:\).*$|\1 Icepack '${versno}'", | g' .zenodo.json +sed -i 's|^\(.*"version":\).*$|\1 "'${versno}'", | g' .zenodo.json +sed -i 's|^\(.*"publication_date":\).*$|\1 "'${cdate}'", | g' .zenodo.json + echo "ICEPACK ${versno}" >! columnphysics/version.txt echo "$0 completed successfully" diff --git a/configuration/scripts/tests/base_suite.ts b/configuration/scripts/tests/base_suite.ts index 9ca13409..b4334f02 100644 --- a/configuration/scripts/tests/base_suite.ts +++ b/configuration/scripts/tests/base_suite.ts @@ -25,9 +25,11 @@ smoke col 1x1 debug,run1year,dyn,fluxopenw smoke col 1x1 debug,run1year,debug,snicartest smoke col 1x1 debug,run1year,debug,snicar smoke col 1x1 debug,run1year,debug,congel +smoke col 1x1 debug,ionetcdf,atmmosaic,ocnmosaic restart col 1x1 debug restart col 1x1 diag1 restart col 1x1 pondlvl +restart col 1x1 pondsealvl restart col 1x1 pondtopo restart col 1x1 bgcispol restart col 1x1 bgcnice diff --git a/configuration/scripts/tests/icepack.lcov.csh b/configuration/scripts/tests/icepack.lcov.csh index 1f9efd09..b3668060 100644 --- a/configuration/scripts/tests/icepack.lcov.csh +++ b/configuration/scripts/tests/icepack.lcov.csh @@ -6,7 +6,19 @@ lcov ${lcovalist} -o total.info set lcovrepo = apcraig.github.io set lcovhtmldir = lcov_icepack_${report_name} -genhtml -o ./${lcovhtmldir} --precision 2 -t "${report_name}" total.info +if ("${useparser}" =~ "true") then + #local parsing script + mkdir ./${lcovhtmldir} + ./parse_lcov.sh >! ./${lcovhtmldir}/${lcovhtmldir}.txt + cat >! ./${lcovhtmldir}/index.html < + +EOF +else + #genhtml + genhtml -o ./${lcovhtmldir} --precision 2 -t "${report_name}" total.info +endif rm -r -f ${lcovrepo} git clone https://github.com/apcraig/${lcovrepo} @@ -14,7 +26,12 @@ cp -p -r ${lcovhtmldir} ${lcovrepo}/ cd ${lcovrepo} set covp0 = `grep message coverage_icepack.json | cut -d : -f 2 | cut -d \" -f 2 | cut -d % -f 1` -set covp = `grep -i headerCovTableEntry ${lcovhtmldir}/index.html | grep % | head -1 | cut -d \> -f 2 | cut -d % -f 1` +if ("${useparser}" =~ "true") then + set covp = `grep "**TOTAL**" ${lcovhtmldir}/${lcovhtmldir}.txt | cut -d \% -f 1` +else + set covp = `grep -i headerCovTableEntry ${lcovhtmldir}/index.html | grep % | head -1 | cut -d \> -f 2 | cut -d \& -f 1` + set covp = "${covp}%" +endif set covpi = `echo $covp | cut -d . -f 1` set lcovhtmlname = "${covpi}%:${report_name}" diff --git a/configuration/scripts/tests/parse_lcov.sh b/configuration/scripts/tests/parse_lcov.sh new file mode 100755 index 00000000..b4733e23 --- /dev/null +++ b/configuration/scripts/tests/parse_lcov.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +INFILE=total.info + +file="ZZZ" +tfunc=0 +thit=0 +tfnd=0 +dacnt=0 +declare -a func +declare -a lines +declare -a linee +declare -a fhit +declare -a ffnd +echo " " + +while read -r LINE +do + case $LINE in + SF:*) + file="${LINE##*/}" + ;; + FN:*) + if [[ "$LINE" =~ ^FN:(.*),(.*),.*_MOD_(.*)$ ]]; then + func[$tfunc]="${BASH_REMATCH[3]}" + lines[$tfunc]="${BASH_REMATCH[1]}" + linee[$tfunc]="${BASH_REMATCH[2]}" + fhit[$tfunc]=0 + ffnd[$tfunc]=0 + tfunc=$(($tfunc + 1)) + fi + ;; + DA:*) + if [[ "$LINE" =~ ^DA:(.*),(.*)$ ]]; then + lnum="${BASH_REMATCH[1]}" + lhit="${BASH_REMATCH[2]}" +# echo "tcx3a ${linee[$dacnt]} $lnum $lhit $dacnt" + if [[ $lnum -lt ${lines[$dacnt]} || $lnum -gt ${linee[$dacnt]} ]]; then + cnt=0 + while [ $cnt -lt $tfunc ]; do + if [[ $lnum -ge ${lines[$cnt]} && $lnum -le ${linee[$cnt]} ]]; then + dacnt=$cnt + fi + cnt=$(($cnt + 1)) + done + fi +# echo "tcx3b $lnum $lhit $dacnt" + ffnd[$dacnt]=$((ffnd[$dacnt] + 1)) + if [[ $lhit -gt 0 ]]; then + fhit[$dacnt]=$((fhit[$dacnt] + 1)) + fi + fi + ;; + LF:*) + fnd="${LINE##*:}" + ;; + LH:*) + hit="${LINE##*:}" + ;; + end_of_record) + thit=$(($thit + $hit)) + tfnd=$(($tfnd + $fnd)) + percent=`echo "scale=2; $hit * 100. / $fnd" | bc` + printf "%6.2f%% %-42s %5d %5d\n" $percent $file $hit $fnd + cnt=0 + while [ $cnt -lt $tfunc ]; do + percent=`echo "scale=2; $((fhit[$cnt] * 100 / ffnd[$cnt]))" | bc` +# printf "%6.2f%% %-40s %5d %5d\n" 0 ${func[$cnt]} ${lines[$cnt]} ${linee[$cnt]} + printf "%12.2f%% %-36s %5d %5d\n" $percent ${func[$cnt]} ${fhit[$cnt]} ${ffnd[$cnt]} + cnt=$(($cnt + 1)) + done + file="ZZZ" + tfunc=0 + dacnt=0 + ;; + *) + ;; + esac + +done < "$INFILE" + +echo " " +#echo "tcx1 $thit $tfnd" +percent=`echo "scale=2; $thit * 100. / $tfnd" | bc` +printf "%6.2f%% %-32s %10d %10d\n" $percent **TOTAL** $thit $tfnd +echo " " diff --git a/configuration/scripts/tests/poll_queue.csh b/configuration/scripts/tests/poll_queue.csh index 0272a1aa..39c53efd 100755 --- a/configuration/scripts/tests/poll_queue.csh +++ b/configuration/scripts/tests/poll_queue.csh @@ -13,10 +13,9 @@ foreach line ("`cat suite.jobs`") set qstatjob = 1 if (${job} =~ [0-9]*) then while ($qstatjob) - ${ICE_MACHINE_QSTAT} $job >&/dev/null - set qstatus = $status -# echo $job $qstatus - if ($qstatus != 0) then + set qstatus = `${ICE_MACHINE_QSTAT} $job | grep $job | wc -l` +# echo $job $qstatus + if ($qstatus == 0) then echo "Job $job completed" set qstatjob = 0 else diff --git a/doc/source/conf.py b/doc/source/conf.py index ba2e0471..ea7ec494 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -55,7 +55,7 @@ # General information about the project. project = u'Icepack' -copyright = u'2024, Triad National Security, LLC (code) and National Center for Atmospheric Research (documentation)' +copyright = u'1998-2026, Triad National Security, LLC (code) and National Center for Atmospheric Research (documentation)' author = u'CICE-Consortium' # The version info for the project you're documenting, acts as replacement for @@ -63,9 +63,9 @@ # built documents. # # The short X.Y version. -version = u'1.5.0' +version = u'1.5.3' # The full version, including alpha/beta/rc tags. -version = u'1.5.0' +version = u'1.5.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/developer_guide/dg_driver.rst b/doc/source/developer_guide/dg_driver.rst index b8389b90..d211ec06 100755 --- a/doc/source/developer_guide/dg_driver.rst +++ b/doc/source/developer_guide/dg_driver.rst @@ -40,7 +40,7 @@ Overview The icepack driver exists to test the column physics. At the present time, it is hardwired to run 4 different gridcells on one processor with the same forcing used for all gridcells. -There is no MPI and no threading built into the icepack driver. There is limited IO capabilities, -no history files, and no netcdf restart files. The model generally runs very quickly. +There is no MPI nor threading built into the icepack driver. There are limited IO capabilities. +The model generally runs very quickly. Forcing data and details on these data are available in :ref:`force`. diff --git a/doc/source/icepack_index.rst b/doc/source/icepack_index.rst index 712d1d89..38b3a4cf 100755 --- a/doc/source/icepack_index.rst +++ b/doc/source/icepack_index.rst @@ -46,6 +46,7 @@ section :ref:`tabnamelist`. "amm", "ammonia/um concentration", "mmol/m\ :math:`^3`" "aparticn", "participation function", "" "apeff_ai", "grid-cell-mean effective pond fraction", "" + "apnd_sl", "equilibrium pond fraction in sealvl ponds", "0.27" "apondn", "area concentration of melt ponds", "" "araftn", "area fraction of rafted ice", "" "ardgn", "fractional area of ridged ice", "" @@ -190,11 +191,15 @@ section :ref:`tabnamelist`. "fswint", "shortwave absorbed in ice interior", "W/m\ :math:`^2`" "fswpenl", "shortwave penetrating through ice layers", "W/m\ :math:`^2`" "fswthru", "shortwave penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_ai", "grid-box-mean shortwave penetrating to ocean (fswthru)", "W/m\ :math:`^2`" + "fswthru_idf", "near IR diffuse shortwave penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_idr", "near IR direct shortwave penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_pardf", "photosynthetically active diffuse shortwave radiation 400-700nm penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_pardr", "photosynthetically active direct shortwave radiation 400-700nm penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_uvrdf", "ultraviolet diffuse shortwave radiation < 400nm penetrating to ocean", "W/m\ :math:`^2`" + "fswthru_uvrdr", "ultraviolet direct shortwave radiation < 400nm penetrating to ocean", "W/m\ :math:`^2`" "fswthru_vdr", "visible direct shortwave penetrating to ocean", "W/m\ :math:`^2`" "fswthru_vdf", "visible diffuse shortwave penetrating to ocean", "W/m\ :math:`^2`" - "fswthru_idr", "near IR direct shortwave penetrating to ocean", "W/m\ :math:`^2`" - "fswthru_idf", "near IR diffuse shortwave penetrating to ocean", "W/m\ :math:`^2`" - "fswthru_ai", "grid-box-mean shortwave penetrating to ocean (fswthru)", "W/m\ :math:`^2`" "fyear", "current data year", "" "fyear_final", "last data year", "" "fyear_init", ":math:`\bullet` initial data year", "" @@ -206,7 +211,9 @@ section :ref:`tabnamelist`. "H2_16O_ocn", "concentration of H2_16O isotope in ocean", "kg/kg" "H2_18O_ocn", "concentration of H2_18O isotope in ocean", "kg/kg" "HDO_ocn", "concentration of HDO isotope in ocean", "kg/kg" + "hbar_init_itd", ":math:`\bullet` initial modal ice thickness for itd-initialized grid cell", "3. m" "hfrazilmin", "minimum thickness of new frazil ice", "0.05 m" + "hi_init_slab", ":math:`\bullet` initial ice thickness for slab-initialized grid cell", "2. m" "hi_min", "minimum ice thickness for thinnest ice category", "m" "hi_ssl", "ice surface scattering layer thickness", "0.05 m" "hicen", "ice thickness in category n", "m" @@ -215,6 +222,7 @@ section :ref:`tabnamelist`. "hin_max", "category thickness limits", "m" "history_format", "turns on netcdf history output if set to 'nc'", "" "hmix", "ocean mixed layer depth", "20. m" + "hmix_fixed", ":math:`\bullet` constant ocean mixed layer depth", "20. m" "hour", "hour of the year", "" "hp0", "pond depth at which shortwave transition to bare ice occurs", "0.2 m" "hp1", ":math:`\bullet` critical ice lid thickness for topo ponds (dEdd)", "0.01 m" @@ -224,6 +232,8 @@ section :ref:`tabnamelist`. "hs0", ":math:`\bullet` snow depth at which transition to ice occurs (dEdd)", "" "hs1", ":math:`\bullet` snow depth of transition to pond ice", "0.03 m" "hs_ssl", "snow surface scattering layer thickness", "0.04 m" + "hsno_init_itd", ":math:`\bullet` initial snow depth for itd-initialized grid cell", "0.25 m" + "hsno_init_slab", ":math:`\bullet` initial snow depth for slab-initialized grid cell", "0. m" "Hstar", "determines mean thickness of ridged ice", "25. m" "**I**", "", "" "i0vis","fraction of penetrating visible solar radiation", "0.70" @@ -243,6 +253,8 @@ section :ref:`tabnamelist`. "istep0", ":math:`\bullet` number of steps taken in previous run", "0" "istep1", "total number of steps at current time step", "" "Iswabs", "shortwave radiation absorbed in ice layers", "W/m\ :math:`^2`" + "itd_area_min", ":math:`\bullet` zap residual ice below a minimum area", "1.e-11" + "itd_mass_min", ":math:`\bullet` zap residual ice below a minimum mass", "1.e-10" "**J**", "", "" "**K**", "", "" "kalg", ":math:`\bullet` absorption coefficient for algae", "" @@ -357,13 +369,15 @@ section :ref:`tabnamelist`. "potT", "atmospheric potential temperature", "K" "PP_net", "total primary productivity per grid cell", "mg C/m\ :math:`^2`/s" "precip_units", ":math:`\bullet` liquid precipitation data units", "" + "precalc_forc", ":math:`\bullet` if true, average/interpolate forcing data on initialization", "" "print_points", ":math:`\bullet` if true, print point data", "F" "Pstar", "ice strength parameter", "2.75\ :math:`\times`\ 10\ :math:`^4`\ N/m\ :math:`^2`" "puny", "a small positive number", "1\ :math:`\times`\ 10\ :math:`^{-11}`" "**Q**", "", "" "Qa", "specific humidity at 10 m", "kg/kg" "Qa_iso", "water isotope specific humidity at 10 m", "kg/kg" - "qdp", "deep ocean heat flux", "W/m\ :math:`^2`" + "qdp", "oceanic heat flux convergence", "W/m\ :math:`^2`" + "qdp_fixed", ":math:`\bullet` constant oceanic heat flux convergence", "0. W/m\ :math:`^2`" "qqqice", "for saturated specific humidity over ice", "1.16378\ :math:`\times`\ 10\ :math:`^7`\ kg/m\ :math:`^3`" "qqqocn", "for saturated specific humidity over ocean", "6.275724\ :math:`\times`\ 10\ :math:`^6`\ kg/m\ :math:`^3`" "Qref", "2m atmospheric reference specific humidity", "kg/kg" @@ -432,7 +446,9 @@ section :ref:`tabnamelist`. "spval_dbl", "special value (double precision)", ":math:`10^{30}`", "" "ss_tltx(y)", "sea surface in the x(y) direction", "m/m" "sss", "sea surface salinity", "ppt" + "sss_fixed", ":math:`\bullet` constant mixed layer salinity", "34. ppt" "sst", "sea surface temperature", "C" + "sst_init", ":math:`\bullet` initial mixed layer temperature", "-1.8\ :math:`^\circ`\ C" "Sswabs", "shortwave radiation absorbed in snow layers", "W/m\ :math:`^2`" "stefan-boltzmann", "Stefan-Boltzmann constant", "5.67\ :math:`\times`\ 10\ :math:`^{-8}` W/m\ :math:`^2`\ K\ :math:`^4`" "stop_now", "if 1, end program execution", "" @@ -483,6 +499,7 @@ section :ref:`tabnamelist`. "tr_lvl", ":math:`\bullet` if true, use level ice area and volume tracers", "" "tr_pond_lvl", ":math:`\bullet` if true, use level-ice melt pond scheme", "" "tr_pond_topo", ":math:`\bullet` if true, use topo melt pond scheme", "" + "tr_pond_sealvl", ":math:`\bullet` if true, use sealvl melt pond scheme", "" "trcr", "ice tracers", "" "trcr_depend", "tracer dependency on basic state variables", "" "Tref", "2m atmospheric reference temperature", "K" diff --git a/doc/source/intro/copyright.rst b/doc/source/intro/copyright.rst index 8ddeef02..d359d19a 100755 --- a/doc/source/intro/copyright.rst +++ b/doc/source/intro/copyright.rst @@ -5,37 +5,9 @@ Copyright ============================= -© Copyright 2024, Triad National Security LLC. All rights reserved. -This software was produced under U.S. Government contract -89233218CNA000001 for Los Alamos National Laboratory (LANL), which is -operated by Triad National Security, LLC for the U.S. Department -of Energy. The U.S. Government has rights to use, reproduce, and distribute -this software. NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC -MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE -OF THIS SOFTWARE. If software is modified to produce derivative works, such -modified software should be clearly marked, so as not to confuse it with the -version available from LANL. - -Additionally, redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -- Neither the name of Triad National Security, LLC, Los Alamos National Laboratory, LANL, the U.S. Government, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY TRIAD NATIONAL SECURITY, LLC AND -CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT -NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TRIAD NATIONAL -SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +© Copyright 1998-2026, Triad National Security, LLC +All rights reserved. +This program was produced under U.S. Government contract 89233218CNA000001 for Los Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC for the U.S. Department of Energy/National Nuclear Security Administration. All rights in the program are reserved by Triad National Security, LLC, and the U.S. Department of Energy/National Nuclear Security Administration. The Government is granted for itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide license in this material to reproduce, prepare. derivative works, distribute copies to the public, perform publicly and display publicly, and to permit others to do so. +This program is Open-Source under the BSD-3 License. diff --git a/doc/source/master_list.bib b/doc/source/master_list.bib index 2296cbd9..f7acf81c 100644 --- a/doc/source/master_list.bib +++ b/doc/source/master_list.bib @@ -252,6 +252,16 @@ @Article{Murray96 pages = {251-273}, url = {http://dx.doi.org/10.1006/jcph.1996.0136} } +@Article{Fetterer98, + author="F. Fetterer and N. Untersteiner", + title="{Observations of melt ponds on Arctic sea ice}", + journal=JGRO, + year={1998}, + volume={103}, + number={C11}, + pages={24821-24835}, + url={https://doi.org/10.1029/98JC02034} +} @Article{Lindsay98 author = "R.W. Lindsay", title = "{Temporal variability of the energy balance of thick Arctic pack ice}", @@ -334,6 +344,16 @@ @Article{Trodahl01 pages = {1279-1282}, url = {http://dx.doi.org/10.1029/2000GL012088} } +@Article{Tschudi01, + author = "M.A. Tschudi and J.A. Curry and J.A. Maslanik", + title = "{Airborne observations of summertime surface features and their effect on surface albedo during FIRE/SHEBA}", + journal = JGRA, + year = {2001}, + volume = {106}, + number = {D14}, + pages = {15335-15344}, + url = {https://doi.org/10.1029/2000JD900275} +} @Manual{Kauffman02 author = "B.G. Kauffman and W.G. Large", title = "{The CCSM coupler, version 5.0.1}", @@ -421,6 +441,15 @@ @Article{Jin06 pages = {63-72}, url = {https://github.com/CICE-Consortium/CICE/blob/master/doc/PDF/JDWSTWLG06.pdf} } +@Article{Brun89 + author = "E. Brun", + title = "{Investigation on wet-snow metamorphism in respect of liquid-water content}", + journal = AG, + year = {1989}, + volume = {13}, + pages = {22-26}, + url = {http://dx.doi.org/10.3189/S0260305500007576} +} @Manual{Briegleb07 author = "B.P. Briegleb and B. Light", title = "{A Delta-Eddington multiple scattering parameterization for solar radiation in the sea ice component of the Community Climate System Model}", @@ -545,6 +574,15 @@ @Article{Lupkes12 number = {D13}, url = {http://dx.doi.org/10.1029/2012JD017630} } +@Article{Polashenski12, + author="C. Polashenski and D. Perovich and Z. Courville", + title="{The mechanisms of sea ice melt pond formation and evolution}", + journal=JGRO, + year={2012}, + volume={117}, + number={C1}, + url={https://doi.org/10.1029/2011JC007231} +} @Article{Hunke13 author = "E.C. Hunke and D.A. Hebert and O. Lecomte", title = "{Level-ice melt ponds in the Los Alamos Sea Ice Model, CICE}", @@ -580,6 +618,16 @@ @Article{Jeffery14 pages = {5891-5920}, url = {http://dx.doi.org/10.1002/2013JC009634} } +@Article{Landy14, + author="J. Landy and J. Ehn and M. Shields and D. Barber", + title="{Surface and melt pond evolution on landfast first-year sea ice in the Canadian Arctic Archipelago}", + journal=JGRO, + year={2014}, + volume={119}, + number={5}, + pages={3054-3075}, + url={https://doi.org/10.1002/2013JC009617} +} @Article{Saha14 author = "S. Saha and S. Moorthi and X. Wu and J. Wang and S. Nadiga and P. Tripp and D Behringer and Y. Hou and H. Chuang and M. Iredell and M. Ek and J. Meng and R. Yang and M.P. Mendez and H. van den Dool and Q. Zhang and W. Wang and M. Chen and E. Becker", title = "{The NCEP Climate Forecast System Version 2}", @@ -619,6 +667,46 @@ @article{Roy15 url = {https://doi.org/10.1002/2014JC010677}, year = {2015} } +@Article{Webster15, + author="M.A. Webster and I.G. Rigor and D.K. Perovich and J.A. Richter-Menge, and C.M. Polashenski and B. Light", + title="{Seasonal evolution of melt ponds on Arctic sea ice}", + year={2015}, + journal=JGRO, + volume={120}, + number={9}, + pages={5968-5982}, + url={https://doi.org/10.1002/2015JC011030} +} +@Article{Wright20, + author="N.C. Wright and C.M. Polashenski and S.T. McMichael and R.A. Beyer", + title="{Observations of sea ice melt from Operation IceBridge imagery}", + year={2020}, + journal=TC, + volume={14}, + number={10}, + pages={3523-3536}, + url={https://doi.org/10.5194/tc-14-3523-2020} +} +@Article{Light22, + author = "B. Light and M.M. Smith and D.K. Perovich and M.A. Webster and M.M. Holland and F. Linhardt and I.A. Raphael and D. Clemens-Sewall and A.R. Macfarlane and P. Anhaus and others", + title = "{Arctic sea ice albedo: Spectral composition, spatial heterogeneity, and temporal evolution observed during the MOSAiC drift}", + year = {2022}, + journal = {Elem Sci Anth}, + volume = {10}, + number = {1}, + pages = {000103}, + url = {https://doi.org/10.1525/elementa.2021.000103} +} +@Article{Webster22, + author="M.A. Webster and M. Holland and N.C. Wright and S. Hendricks and N. Hutter and P. Itkin and B. Light and F. Linhardt and D.K. Perovich and I.A. Raphael and M.M. Smith and L.v. Albedyll and J. Zhang", + title="{Spatiotemporal evolution of melt ponds on Arctic sea ice: MOSAiC observations and model results}", + year={2022}, + journal={Elem Sci Anth}, + volume={10}, + number={1}, + pages={000072}, + url={https://doi.org/10.1525/elementa.2021.000072} +} @Article{Duarte17 author = "P. Duarte and Coauthors", title = "{Sea ice thermohaline dynamics and biogeochemistry in the Arctic Ocean: Empirical and model results}", @@ -843,6 +931,25 @@ @article{Edwards2012 doi = {https://doi.org/10.4319/lo.2012.57.2.0554}, year = {2012} } +@article{Raphael24, +author = "Raphael, I.A. and Perovich, D.K. and Polashenski, C.M. and Clemens-Sewall, D. and Itkin, P. and Lei, R. and Nicolaus, M. and Regnery, J. and Smith, M.M. and Webster, M. and Jaggi, M.", +title = {Sea ice mass balance during the {MOSAiC} drift experiment: {Results} from manual ice and snow thickness gauges}, +volume = {12}, +issn = {2325-1026}, +url = {https://doi.org/10.1525/elementa.2023.00040}, +doi = {10.1525/elementa.2023.00040}, +number = {1}, +journal = {Elementa: Science of the Anthropocene}, +year = {2024}, +pages = {00040}, +} +@misc{Clemens-Sewall25 +author = "Clemens-Sewall, D. and Cox, C. and Schulz, K. and Raphael, I. and Persson, O. and Shupe, M. and Smith, M.", +title = "{Merged Datasets for the Multidisciplinary drifting Observatory for the Study of Arctic Climate (MOSAiC) Central Observatory in the Arctic Ocean (2019-2020) version 2}", +year = {2025}, +doi = {https://doi.org/10.18739/A2WD3Q35Z}, +howpublished = {Arctic Data Center} +} % ********************************************** % For new entries, see example entry in BIB_TEMPLATE.txt % ********************************************** diff --git a/doc/source/science_guide/sg_bgc.rst b/doc/source/science_guide/sg_bgc.rst index b38b2713..04db1f88 100755 --- a/doc/source/science_guide/sg_bgc.rst +++ b/doc/source/science_guide/sg_bgc.rst @@ -456,12 +456,6 @@ flags in **icepack\_in** must be true: a) ``tr_brine``, b) ``z_tracers``, and c) This is appropriate for the black carbon and dust aerosols specified by ``tr_zaero`` true. -.. zsalinity is being deprecated -.. In addition, a halodynamics scheme must also be used. The default -.. thermo-halodynamics is mushy layer ``ktherm`` set to 2. An alternative uses -.. the Bitz and Lipscomb thermodynamics ``ktherm`` set to 1 and ``solve_zsal`` -.. true (referred to as "zsalinity"). - With the above flags and ``tr_bgc_Nit`` set to true, the default biochemistry is a simple algal-nitrate system: ``tr_bgc_N`` (turned on by default) and ``tr_bgc_Nit`` (required). Options exist in **icepack\_in** to use a more complicated ecosystem which includes up diff --git a/doc/source/science_guide/sg_boundary_forcing.rst b/doc/source/science_guide/sg_boundary_forcing.rst index ce4f10e0..e73a13a9 100755 --- a/doc/source/science_guide/sg_boundary_forcing.rst +++ b/doc/source/science_guide/sg_boundary_forcing.rst @@ -88,7 +88,17 @@ stable and accurate procedure would be to compute the temperature profiles for both the atmosphere and ice, together with the surface fluxes, in a single implicit calculation. This was judged impractical, however, given that the atmosphere and sea ice models generally exist on -different grids and/or processor sets. +different grids and/or processor sets. In NASA GMAO GEOS-ESM coupled model, +a semi-implicit thermodynamic coupling scheme is introduced. Similar to the explicit +case, the fields ``fsurfn`` are provided by the coupler, along with their derivatives +with respect to surface temperature ``dfsurfn_dTs``. In this case, ``calc_Tsfc`` +is still set to true, allowing ice surface and internal temperature to be updated +implicitly. The resultant surface temperature change is passed back to the +atmosphere model via coupler to complete the full update of its temperature profiles. +This middle-ground approach, enabled by ``vapor_flux_correction=true``, does not sacrifice +accuracy because it does not need effective conductivity limiting as in the explicit case. + + .. _atmo: diff --git a/doc/source/science_guide/sg_snow.rst b/doc/source/science_guide/sg_snow.rst index 751fd874..59a151c1 100755 --- a/doc/source/science_guide/sg_snow.rst +++ b/doc/source/science_guide/sg_snow.rst @@ -123,7 +123,7 @@ 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 :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. 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. +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 layer's holding capacity, or irreducible saturation level, is a namelist option, ``snwliq_max``, with values ranging from about 0.03 to approximately 0.1 (:cite:`Brun89`). 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. @@ -140,7 +140,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 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``. +Following :cite:`Oleson10` and :cite:`Brun89`, the new snow grain radius tracer is a weighted function of existing and new (freshly fallen, ``rsnw_fall``) snow grain radii. The snow grain radius grows over time via two processes: temperature gradient (or dry) metamorphism and wet metamorphism. Temperature gradient metamorphism growth rates are determined using parameters from a look-up table that depends on snow temperature, temperature gradient and (effective) density as described in :cite:`Flanner06`. Wet metamorphism growth rates depend on the snow liquid fraction, :math:`f_{liq}=m_{liq}/(m_{ice}+m_{liq})`. The overall magnitude of the wet metamorphism rate is controlled by the namelist parameter, ``snw_growth_wet``. When no liquid is present in snow, :cite:`Brun89` observe a minimum snow grain growth rate, :math:`drsnw_min_o`. In our formulation, the total snow grain growth rate is the sum of the growth rates from dry and wet metamorphism, with the requirement that the dry metamorphism rate be greater than or equal to a minimum growth rate. This minimum rate is adjusted through the namelist parameter ``drsnw_min`` which is a unitless scaling of :math:`drsnw_min_o`. The maximum snow radius is also a namelist option, ``rsnw_tmax``. diff --git a/doc/source/science_guide/sg_thermo.rst b/doc/source/science_guide/sg_thermo.rst index 1577a7e5..bf3d3c25 100755 --- a/doc/source/science_guide/sg_thermo.rst +++ b/doc/source/science_guide/sg_thermo.rst @@ -88,11 +88,11 @@ because the infiltration of snow by pond water accomplishes the gradual radiativ transition for which the patchy-snow parameters were originally intended. When level-ice ponds are not used, then a typical value for hs0 is 0.03. -With level-ice ponds, the pond water is allowed to infiltrate snow over the level ice area, +With level-ice ponds, the pond water is allowed to infiltrate snow over the level-ice area, invisible to the radiation scheme, until the water becomes deep enough to show through the snow layer. The pond fraction is computed during this process and then used to -set the snow fraction such that :math:`f_{snow}+f_{pond}=1`. The ponds are only on the level ice -area, and so there is still snow on the ridges even if the entire level ice area becomes filled +set the snow fraction such that :math:`f_{snow}+f_{pond}=1`. The ponds are only on the level-ice +area, and so there is still snow on the ridges even if the entire level-ice area becomes filled with ponds. See :cite:`Hunke13` for a discussion of the impacts of varying hs1, whose default value is 0.03. @@ -116,7 +116,7 @@ be added to the melt pond liquid volume: \Delta V_{melt} = {r\over\rho_w} \left({\rho_{i}}\Delta h_{i} + {\rho_{s}}\Delta h_{s} + F_{rain}{\Delta t}\right) a_i, :label: meltvol -where +For the topo pond parameterization and the level-ice pond parameterization .. math:: r = r_{min} + \left(r_{max} - r_{min}\right) a_i @@ -127,8 +127,11 @@ ponds, :math:`\rho_i` and :math:`\rho_s` are ice and snow densities, :math:`\Delta h_i` and :math:`\Delta h_s` are the thicknesses of ice and snow that melted, and :math:`F_{rain}` is the rainfall rate. Namelist parameters are set for the level-ice (``tr_pond_lvl``) parameterization; -in the cesm and topo pond schemes the standard values of :math:`r_{max}` -and :math:`r_{min}` are 0.7 and 0.15, respectively. +in the topo pond scheme the standard values of :math:`r_{max}` +and :math:`r_{min}` are 0.7 and 0.15, respectively. For the sea-level pond +parameterization, 100% of the melt water is added to the ponds +(:math:`r = 1.0`) and runoff is handled by the macro-flaw drainage +parameterization. Radiatively, the surface of an ice category is divided into fractions of snow, pond and bare ice. In these melt pond schemes, the actual pond @@ -441,8 +444,7 @@ given by the parameter :math:`\delta_p` (``pndaspect``), :math:`\Delta V = \Delta h_p \Delta a_{p} = \delta_p\Delta a_p^2 = \Delta h_{p}^2/\delta_p`. Here, :math:`a_{p} = a_{pnd} a_{lvl}`, the mean pond area over the ice. -Given the ice velocity :math:`\bf u`, conservation equations for level -ice fraction :math:`a_{lvl}a_i`, pond area fraction +Given the ice velocity :math:`\bf u`, conservation equations for level-ice fraction :math:`a_{lvl}a_i`, pond area fraction :math:`a_{pnd}a_{lvl}a_i`, pond volume :math:`h_{pnd}a_{pnd}a_{lvl}a_i` and pond ice volume :math:`h_{ipnd}a_{pnd}a_{lvl}a_i` are @@ -467,7 +469,7 @@ and pond ice volume :math:`h_{ipnd}a_{pnd}a_{lvl}a_i` are conservation of melt pond volume and pond ice volume, but in this form highlight that the quantities tracked in the code are the tracers :math:`h_{pnd}` and :math:`h_{ipnd}`, pond depth and pond ice thickness. -Likewise, the level ice fraction :math:`a_{lvl}` is a tracer on ice area +Likewise, the level-ice fraction :math:`a_{lvl}` is a tracer on ice area fraction (Equation :eq:`transport-lvl`), and pond fraction :math:`a_{pnd}` is a tracer on level ice (Equation :eq:`transport-apnd-lvl`). @@ -669,7 +671,7 @@ where :math:`d_p` is a scaling factor (dpscale), and dynamic viscosity. *Conservation elsewhere.* When ice ridges and when new ice forms in open -water, the level ice area changes and ponds must be handled +water, the level-ice area changes and ponds must be handled appropriately. For example, when sea ice deforms, some of the level ice is transformed into ridged ice. We assume that pond water (and ice) on the portion of level ice that ridges is lost to the ocean. All of the @@ -692,6 +694,183 @@ same mean pond area in a grid cell after the addition of new ice, and solving for the new pond area tracer :math:`a_{pnd}^\prime` given the newly formed ice area :math:`\Delta a_i = \Delta a_{lvl}`. +Sea-level pond formulation (``tr_pond_sealvl`` = true) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The sea-level meltpond parameterization was developed based on the +following observations from field studies and high-resolution (<=1 m) +satellite and airborne imagery: + +* Stage I and II of melt pond formation (initial formation and + drainage to sea level, respectively) last approximately 2 weeks + :cite:`Eicken04`, :cite:`Polashenski12`, :cite:`Landy14`. + Therefore melt ponds spend most of their lifespan in Stage III (i.e., + pond-air interfaces are at or near sea level and pond-ice interfaces + are below sea level). +* On the scale of a CICE grid cell (> 1 km), melt ponds are + simultaneously observed on thicker and thinner ice; thinner ice + does not need to be saturated with ponds for there to be ponds on + thicker ice :cite:`Webster15`, :cite:`Webster22`. +* For pack ice in the Arctic, Stage III melt pond fraction is rarely + observed to be below 15% or above 45% on the scale of a CICE grid cell + (e.g., :cite:`Fetterer98`, :cite:`Tschudi01`, :cite:`Webster15`, + :cite:`Wright20`). Some remote sensing retrievals show higher + pond fractions immediately before the ice melts out :cite:`Webster15`, + but it is possible that melted-through ponds (i.e., + open water) are being misclassified as ponds. +* Ponds are routinely observed on deformed ice (e.g., :cite:`Eicken04`). +* When MYI and FYI coexist, observations do not clearly indicate + consistent differences in pond fraction, although there may be + differences in timing :cite:`Webster15`, :cite:`Wright20`. +* Ponded ice albedos do not rapidly increase as pond depth decreases + below 20 cm :cite:`Light22`. + +The sealvl parameterization assumes that each ice thickness category +within the grid cell has a subcategory distribution of ice surface +height relative to sea level (a.k.a. a hypsometric curve). Meltwater +is assumed to pool at the lowest ice surface height within the category +and meltwater does not laterally advect between categories on its own +(it is still handled as a tracer on ice area and hence advects with +ice thickness changes). The hypsometric curve is assumed to be linear. +For each category, the slope and intercept of the hypsometric curve are +parameterized such that when pond surfaces are at sea level and the +category is snow-free, the pond area fraction is equal to the namelist +parameter ``apnd_sl`` (notated as :math:`a_{p,sl}` in Eq. :eq:`pndasp`). +Unless otherwise specified, the sealvl parameterization uses the same +parameterizations as the level-ice pond scheme. For example, the same +approach is used to set the effective surface fractions for the Delta- +Eddington shortwave calculations. + +*Hypsometry and Pond Depth-Area Relationship.* + +Because sea ice is floating, the intercept of the hypsometric curve is +determined by buoyancy. In this construction, the slope of the +hypsometric curve is equal to double the pond aspect ratio +(:math:`pndasp`), which is defined such that + +.. math:: + h_p = a_p * pndasp + +where :math:`h_p` is the mean depth of the ponded area of the +category and :math:`a_p` is the pond area fraction of the category. +Pond meltwater volume is apportioned into depth and area according to +:math:`pndasp`, with the exception that if the pond area completely +fills the category :math:`h_p` may exceed :math:`a_p*pndasp` +(:math:`h_p` is still subject to a freeboard constraint). +Unlike in the level-ice parameterization, this use of :math:`pndasp` means +that when drainage reduces pond volume, both pond area and depth +decrease; in the level-ice parameterization just depth decreases. In the +sealvl parameterization, pond aspect is calculated by + +.. math:: + pndasp = h_{in}*(\rho_w - \rho_{si}) / (\rho_{fresh} * (a_{p,sl})^2 - 2 \rho_w * a_{p,sl} + \rho_w) + :label: pndasp + +where :math:`h_{in}` is the ice thickness of the category. +:math:`\rho_w`, :math:`\rho_{si}`, and :math:`\rho_{fresh}` are the +densities of ocean water, sea ice, and pond water respectively. Note +that for simplicity we use a constant sea ice density instead of using +the mushy parameterization. + +The weight of the snow is omitted from the calculation of :math:`pndasp`. +The impact of this omission is that pond area and depth will tend to be +slightly higher while the category still has snow on it (i.e., in Stage +I). Since pond fractions are typically highest in Stage I +(:cite:`Eicken04`, :cite:`Polashenski12`), this was seen as a +desirable feature, although future work should explicitly parameterize +how the hypsometry and drainage evolves at different stages of pond +evolution. + +The parameterized hypsometric curve is also used to compute the height +of the pond surfaces above the mean ice draft (:math:`hpsurf`), which is +then used in the calculation of hydraulic head for the drainage +parameterizations. :math:`hpsurf` is calculated by + +.. math:: + hpsurf = h_{in} - pndasp + 2 * pndasp * a_{p} + :label: hpsurf + +Unlike in the level-ice pond scheme, ponds are not limited to the level-ice +fraction. Currently the parameterization of the hypsometric curve does +not account for the impacts of deformed ice due to limited data. Future +research should target this limitation. + +*Drainage and Pond Lid Refreezing.* + +There are five mechanisms by which water can be lost from melt ponds in +the sealvl parameterization: percolation through the ice (sub-cm scale +drainage), drainage through macroscopic flaws in the ice (super-cm scale), an +ice freeboard constraint, drainage during ice deformation, and pond lid +refreezing. Meltwater is also lost when the ice melts. Unlike in the +level-ice or topo schemes, the sealvl scheme does not use the 'runoff' +(``rfrac``) parameterization. Instead of draining a portion of the total +meltwater before it reaches the ponds via rfrac as in the topo and +level-ice schemes, this water is handled by the macro-scale drainage +in the sealvl scheme. + +* *Percolation Drainage.* Percolation drainage is implemented in the mushy + thermodynamics scheme. The harmonic mean of the permeability of the + ice column is estimated, as is the hydraulic head (the height of the + pond-air interface above sea level). Then the drainage rate + is estimated assuming a Darcy flow. Percolation drainage in the sealvl + scheme is identical to the level-ice scheme except for the calculation of + the hydraulic head. + +* *Macro-Flaw Drainage.* Melt water is transported laterally and drains + through macroscopic flaws: cracks, floe edges, enlarged brine channels, + seal holes, etc. (:cite:`Eicken04`, :cite:`Polashenski12`). In the + real system, the efficiency of this process depends on the + connectivity of lateral flow networks and the frequency of + macroscopic flaws, both of which evolve with ice conditions. In the sealvl + scheme, macro-flaw drainage is parameterized as an exponential decay + of pond height relative to sea level (a.k.a., the hydraulic head), so + macro-flaw drainage cannot remove pond water that sits below sea + level. The level-ice pond scheme is identical except that the exponential + decay is applied to the entire pond height. The decay constant is + controlled by the ``tscale_pnd_drain`` namelist parameter. Currently, + this decay constant is uniform in time and space, but future work + should consider how changing ice conditions impact macro-flaw + drainage. + +* *Ice Freeboard Constraint.* For free-floating ice, pond water cannot + depress the mean ice surface below sea level when there are efficient + water transport pathways (i.e., Stage III melt ponds). The buoyancy + force from the ice drives the redistribution of water from above the + ice to below. Below-sea-level pond bottoms are sustained by the weight + of adjacent ice and snow above sea level. The sealvl scheme assumes + that each ice category is rigid and mechanically uncoupled from the + other categories. If necessary, pond water is drained such that the + mean ice surface of the category is at sea level. I.e., the mean + category ice freeboard is constrained to be greater than or equal to + zero. The level-ice pond scheme has the same constraint, except in the + level-ice pond scheme the ponded area of the category is assumed to be + mechanically uncoupled from the surrounding ice. + +* *Drainage During Ice Deformation.* In all of the pond schemes, it is + assumed that all pond water drains from ice undergoing deformation. + +* *Pond Lid Refreezing.* Pond lid refreezing and melting in the sealvl + scheme is handled in the same manner as in the level-ice scheme. + The only difference is that in the sealvl scheme the impact of the + removed/added pond water are distributed according to hypsometry. + +*Pond Depth and Optical Property Relationship.* + +When the Delta-Eddington radiation transport scheme +(:cite:`Briegleb07`) was implemented, there were no observations of +albedo in ponds shallower than 20 cm. For ponds shallower than a +transition depth (``hp0``, default 0.2 m), it was assumed that the +inherent optical properties (IOPs) were represented by a mixture of +ponded ice IOPs and bare ice IOPs, in proportions determined by the pond +depth. Additionally, if ponds are shallower than a cutoff depth +(``hpmin``, default 0.005 m) they are assumed to have no impact on the +optical properties (bare ice IOPs are used). Subsequent research +(e.g., :cite:`Light22`) does not support the assumption of a gradual +transition to bare ice IOPs below 20 cm pond depth. The presence of a +pond of any measured depth was sufficient to change the apparent optical +properties. Consequently, the sealvl scheme disables the pond to bare +ice transition depth assumption (``hp0`` = ``hpmin`` = 0.005 m). + .. _sfc-forcing: Thermodynamic surface forcing balance @@ -710,19 +889,27 @@ heat flux, :math:`F_{L\downarrow}` is the incoming longwave flux, :math:`F_{L\uparrow}` is the outgoing longwave flux, :math:`F_{sw}` is the incoming shortwave flux, :math:`\alpha` is the shortwave albedo, and :math:`i_0` is the fraction of absorbed shortwave flux that penetrates -into the ice. The albedo may be altered by the presence of melt ponds. -Each of the explicit melt pond parameterizations (CESM, topo and -level-ice ponds) should be used in conjunction with the Delta-Eddington -shortwave scheme, described below. +into the ice. + +Two methods for computing albedo and shortwave fluxes are available, the +"CCSM3" method and a multiple scattering radiative transfer scheme that +uses a Delta-Eddington approach. Shortwave forcing input is generally +divided into two wavelength bands (:math:`< 700` \ nm, visible and below) and +(:math:`> 700` \ nm, infrared), with an additional capability to accept +shortwave divided into ultraviolet (:math:`< 400` \ nm) and visible / +photosynthetically active (:math:`400 - 700` \ nm) bands. +Radiation calculations may occur in the original two bands +or for up to five bands, as described below. + +The albedo may be altered by the presence of melt ponds. +Each of the explicit melt pond parameterizations (topo, level-ice and +sealvl ponds) should be used in conjunction with the Delta-Eddington +shortwave scheme. Shortwave radiation: Delta-Eddington ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Two methods for computing albedo and shortwave fluxes are available, the -"ccsm3" method, described in the next section, and a multiple scattering -radiative transfer scheme that uses a Delta-Eddington approach -(``shortwave`` = ``dEdd``). - +In the Delta-Eddington approach (``shortwave`` = ``dEdd``), "Inherent" optical properties (IOPs) for snow and sea ice, such as extinction coefficient and single scattering albedo, are prescribed based on physical measurements; reflected, absorbed and transmitted @@ -1787,6 +1974,16 @@ as the product of sensitivity studies to balance the climatological tendencies o wave fracture and welding. So that results do not vary as the number or range of floe size categories varies, we fix this scaling coefficient, c_weld. +If ``tr_fsd=false``, lateral melting is accomplished by multiplying the state variables by +:math:`1-r_{side}`, where :math:`r_{side}` is the fraction of ice melted +laterally :cite:`Maykut87,Steele92`, and adjusting the ice +energy and fluxes as appropriate. We assume a floe diameter of 300 m. + +If ``tr_fsd=true``, lateral melting is accomplished using the :cite:`Maykut87` +lateral heat flux, but applied to the ice using the prognostic floe size distribution +as described in :cite:`Horvat15` and :cite:`Roach18`. Lateral melt modifies +the ITD and the FSD. + If the latent heat flux is negative (i.e., latent heat is transferred from the ice to the atmosphere), snow or snow-free ice sublimates at the top surface. If the latent heat flux is positive, vapor from the @@ -1802,7 +1999,12 @@ ice), and :math:`L_v = 2.501 \times 10^6 \ \mathrm{J/kg}` is the latent heat of vaporization of liquid water at :math:`0^{\circ}C`. Note that :math:`\rho L_v` is nearly an order of magnitude larger than typical values of :math:`q`. For positive latent heat fluxes, the deposited snow or ice is assumed to -have the same enthalpy as the existing surface layer. +have the same enthalpy as the existing surface layer. Some climate models (for +example, GEOS-ESM) compute mass flux (sublimation or deposition) in the atmsophere +model which assumes vapor deposits or sublimates at 0 degC. In this case, mass +conservation is enforced and the resulting discrepancy in energy is resolved by +another term ``de_vapor`` and passed to ocean. This option is only on when +``semi-implicit_Tsfc=true``. After growth and melting, the various ice layers no longer have equal thicknesses. We therefore adjust the layer interfaces, conserving @@ -1820,15 +2022,11 @@ old and new layers, respectively. The enthalpies of the new layers are .. math:: q_k = \frac{1}{\Delta h_i} \sum_{m=1}^{N_i} \eta_{km} q_m. -If ``tr_fsd=false``, lateral melting is accomplished by multiplying the state variables by -:math:`1-r_{side}`, where :math:`r_{side}` is the fraction of ice melted -laterally :cite:`Maykut87,Steele92`, and adjusting the ice -energy and fluxes as appropriate. We assume a floe diameter of 300 m. - -If ``tr_fsd=true``, lateral melting is accomplished using the :cite:`Maykut87` -lateral heat flux, but applied to the ice using the prognostic floe size distribution -as described in :cite:`Horvat15` and :cite:`Roach18`. Lateral melt modifies -the ITD and the FSD. +Residual amounts of ice may be conservatively removed following the thermodynamics +and ridging calculations based on minimum area and mass parameters ``itd_area_min`` and +``itd_mass_min``. Initializing these parameters to CICE's ``dyn_area_min`` and ``dyn_mass_min`` +namelist values ensures consistency between Icepack's thermodynamic and CICE's +dynamic calculations and avoids tiny amounts of residual ice in the solution. Snow-ice formation ------------------ diff --git a/doc/source/user_guide/interfaces.include b/doc/source/user_guide/interfaces.include index b28eff1a..3620e5c1 100644 --- a/doc/source/user_guide/interfaces.include +++ b/doc/source/user_guide/interfaces.include @@ -100,32 +100,6 @@ icepack_init_hbrine -.. _icepack_init_zsalinity: - -icepack_init_zsalinity -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. code-block:: fortran - - ! **DEPRECATED**, all code removed - ! Interface provided for backwards compatibility - - subroutine icepack_init_zsalinity(Rayleigh_criteria, & - Rayleigh_real, trcrn_bgc, sss) - - logical (kind=log_kind), intent(inout) :: & - Rayleigh_criteria - - real (kind=dbl_kind), intent(inout):: & - Rayleigh_real - - real (kind=dbl_kind), intent(in):: & - sss - - real (kind=dbl_kind), dimension(:,:), intent(inout):: & - trcrn_bgc ! bgc subset of trcrn - - - icepack_fsd.F90 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -279,7 +253,6 @@ icepack_intfc.F90 use icepack_shortwave, only: icepack_step_radiation use icepack_brine, only: icepack_init_hbrine - use icepack_brine, only: icepack_init_zsalinity ! deprecated use icepack_zbgc , only: icepack_init_bgc use icepack_zbgc , only: icepack_init_zbgc @@ -489,9 +462,9 @@ icepack_step_ridge dvirdgndt, & araftn, vraftn, & aice, fsalt, & - first_ice, fzsal, & + first_ice, & flux_bio, closing, & - Tf, & + Tf, dpnd_ridge, & docleanup, dorebin) real (kind=dbl_kind), intent(in) :: & @@ -531,9 +504,6 @@ icepack_step_ridge fsalt , & ! salt flux to ocean (kg/m^2/s) fhocn ! net heat flux to ocean (W/m^2) - real (kind=dbl_kind), intent(inout), optional :: & - fzsal ! zsalinity flux to ocean(kg/m^2/s) (deprecated) - real (kind=dbl_kind), intent(inout), optional :: & closing ! rate of closing due to divergence/shear (1/s) @@ -567,6 +537,9 @@ icepack_step_ridge logical (kind=log_kind), dimension(:), intent(inout) :: & first_ice ! true until ice forms + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_ridge ! pond drainage due to ridging + logical (kind=log_kind), intent(in), optional :: & docleanup, & ! if false, do not call cleanup_itd (default true) dorebin ! if false, do not call rebin in cleanup_itd (default true) @@ -807,16 +780,15 @@ icepack_init_parameters stefan_boltzmann_in, ice_ref_salinity_in, & Tffresh_in, Lsub_in, Lvap_in, Timelt_in, Tsmelt_in, & iceruf_in, Cf_in, Pstar_in, Cstar_in, kappav_in, & - kice_in, ksno_in, & + kice_in, ksno_in, itd_area_min_in, itd_mass_min_in, & zref_in, hs_min_in, snowpatch_in, rhosi_in, sk_l_in, & - saltmax_in, phi_init_in, min_salin_in, salt_loss_in, & - Tliquidus_max_in, & + saltmax_in, phi_init_in, min_salin_in, Tliquidus_max_in, & min_bgc_in, dSin0_frazil_in, hi_ssl_in, hs_ssl_in, hs_ssl_min_in, & awtvdr_in, awtidr_in, awtvdf_in, awtidf_in, & qqqice_in, TTTice_in, qqqocn_in, TTTocn_in, & - ktherm_in, conduct_in, fbot_xfer_type_in, calc_Tsfc_in, dts_b_in, & + ktherm_in, conduct_in, fbot_xfer_type_in, calc_Tsfc_in, & update_ocn_f_in, ustar_min_in, hi_min_in, a_rapid_mode_in, & - cpl_frazil_in, & + cpl_frazil_in, semi_implicit_Tsfc_in, vapor_flux_correction_in, & Rac_rapid_mode_in, aspect_rapid_mode_in, & dSdt_slow_mode_in, phi_c_slow_mode_in, & phi_i_mushy_in, shortwave_in, albedo_type_in, albsnowi_in, & @@ -826,13 +798,12 @@ icepack_init_parameters atmbndy_in, calc_strair_in, formdrag_in, highfreq_in, natmiter_in, & atmiter_conv_in, calc_dragio_in, & tfrz_option_in, kitd_in, kcatbound_in, hs0_in, frzpnd_in, & - saltflux_option_in, congel_freeze_in, & - floeshape_in, wave_spec_in, wave_spec_type_in, nfreq_in, & + apnd_sl_in, saltflux_option_in, congel_freeze_in, & + floeshape_in, wave_spec_in, wave_spec_type_in, wave_height_type_in, nfreq_in, & dpscale_in, rfracmin_in, rfracmax_in, pndaspect_in, hs1_in, hp1_in, & bgc_flux_type_in, z_tracers_in, scale_bgc_in, solve_zbgc_in, & modal_aero_in, use_macromolecules_in, restartbgc_in, skl_bgc_in, & - solve_zsal_in, grid_o_in, l_sk_in, & - initbio_frac_in, grid_oS_in, l_skS_in, dEdd_algae_in, & + grid_o_in, l_sk_in, initbio_frac_in, dEdd_algae_in, & phi_snow_in, T_max_in, fsal_in, use_atm_dust_iron_in, & fr_resp_in, algal_vel_in, R_dFe2dust_in, dustFe_sol_in, & op_dep_min_in, fr_graze_s_in, fr_graze_e_in, fr_mort2min_in, & @@ -841,6 +812,7 @@ 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, snwgrain_in, & snwredist_in, use_smliq_pnd_in, rsnw_fall_in, rsnw_tmax_in, & + snw_growth_wet_in, drsnw_min_in, snwliq_max_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, & @@ -932,7 +904,6 @@ icepack_init_parameters saltmax_in, & ! max salinity at ice base for BL99 (ppt) phi_init_in, & ! initial liquid fraction of frazil min_salin_in, & ! threshold for brine pocket treatment - salt_loss_in, & ! fraction of salt retained in zsalinity Tliquidus_max_in, & ! maximum liquidus temperature of mush (C) dSin0_frazil_in ! bulk salinity reduction of newly formed frazil @@ -951,10 +922,12 @@ icepack_init_parameters calc_Tsfc_in , &! if true, calculate surface temperature ! if false, Tsfc is computed elsewhere and ! atmos-ice fluxes are provided to CICE + semi_implicit_Tsfc_in , &! compute dfsurf/dT, dflat/dT terms instead of fsurf, flat + vapor_flux_correction_in, &! compute mass/enthalpy correction when evaporation/sublimation + ! computed outside at 0C update_ocn_f_in ! include fresh water and salt fluxes for frazil real (kind=dbl_kind), intent(in), optional :: & - dts_b_in, & ! zsalinity timestep hi_min_in, & ! minimum ice thickness allowed (m) for thermo ustar_min_in ! minimum friction velocity for ice-ocean heat flux @@ -1037,14 +1010,16 @@ icepack_init_parameters !----------------------------------------------------------------------- real(kind=dbl_kind), intent(in), optional :: & - Cf_in, & ! ratio of ridging work to PE change in ridging - Pstar_in, & ! constant in Hibler strength formula - Cstar_in, & ! constant in Hibler strength formula - dragio_in, & ! ice-ocn drag coefficient + itd_area_min_in, & ! zap residual ice below this minimum area + itd_mass_min_in, & ! zap residual ice below this minimum mass + Cf_in, & ! ratio of ridging work to PE change in ridging + Pstar_in, & ! constant in Hibler strength formula + Cstar_in, & ! constant in Hibler strength formula + dragio_in, & ! ice-ocn drag coefficient thickness_ocn_layer1_in, & ! thickness of first ocean level (m) - iceruf_ocn_in, & ! under-ice roughness (m) - gravit_in, & ! gravitational acceleration (m/s^2) - iceruf_in ! ice surface roughness (m) + iceruf_ocn_in, & ! under-ice roughness (m) + gravit_in, & ! gravitational acceleration (m/s^2) + iceruf_in ! ice surface roughness (m) integer (kind=int_kind), intent(in), optional :: & ! defined in namelist kstrength_in , & ! 0 for simple Hibler (1979) formulation @@ -1116,7 +1091,8 @@ icepack_init_parameters wave_spec_in ! if true, use wave forcing character (len=*), intent(in), optional :: & - wave_spec_type_in ! type of wave spectrum forcing + wave_spec_type_in, & ! type of wave spectrum forcing + wave_height_type_in ! type of wave height forcing !----------------------------------------------------------------------- ! Parameters for biogeochemistry @@ -1139,20 +1115,15 @@ icepack_init_parameters conserv_check_in ! if .true., run conservation checks and abort if checks fail logical (kind=log_kind), intent(in), optional :: & - skl_bgc_in, & ! if true, solve skeletal biochemistry - solve_zsal_in ! if true, update salinity profile from solve_S_dt + skl_bgc_in ! if true, solve skeletal biochemistry real (kind=dbl_kind), intent(in), optional :: & grid_o_in , & ! for bottom flux - l_sk_in , & ! characteristic diffusive scale (zsalinity) (m) + l_sk_in , & ! characteristic diffusive scale (m) grid_o_t_in , & ! top grid point length scale initbio_frac_in, & ! fraction of ocean tracer concentration used to initialize tracer phi_snow_in ! snow porosity at the ice/snow interface - real (kind=dbl_kind), intent(in), optional :: & - grid_oS_in , & ! for bottom flux (zsalinity) - l_skS_in ! 0.02 characteristic skeletal layer thickness (m) (zsalinity) - real (kind=dbl_kind), intent(in), optional :: & ratio_Si2N_diatoms_in, & ! algal Si to N (mol/mol) ratio_Si2N_sp_in , & @@ -1286,7 +1257,7 @@ icepack_init_parameters real (kind=dbl_kind), intent(in), optional :: & hs0_in ! snow depth for transition to bare sea ice (m) - ! level-ice ponds + ! level-ice and sealvl ponds character (len=*), intent(in), optional :: & frzpnd_in ! pond refreezing parameterization @@ -1297,6 +1268,10 @@ icepack_init_parameters pndaspect_in, & ! ratio of pond depth to pond fraction hs1_in ! tapering parameter for snow on pond ice + ! sealvl ponds + real (kind=dbl_kind), intent(in), optional :: & + apnd_sl_in ! equilibrium pond fraction for sea level parameterization + ! topo ponds real (kind=dbl_kind), intent(in), optional :: & hp1_in ! critical parameter for pond ice thickness @@ -1321,7 +1296,10 @@ 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 + snw_growth_wet_in,&! wet metamorphism parameter (um^3/s) + drsnw_min_in, & ! minimum snow grain growth factor + snwliq_max_in ! irreducible saturation fraction integer (kind=int_kind), intent(in), optional :: & isnw_T_in, & ! maxiumum temperature index @@ -1366,31 +1344,29 @@ icepack_query_parameters stefan_boltzmann_out, ice_ref_salinity_out, & Tffresh_out, Lsub_out, Lvap_out, Timelt_out, Tsmelt_out, & iceruf_out, Cf_out, Pstar_out, Cstar_out, kappav_out, & - kice_out, ksno_out, & + kice_out, ksno_out, itd_area_min_out, itd_mass_min_out, & zref_out, hs_min_out, snowpatch_out, rhosi_out, sk_l_out, & - saltmax_out, phi_init_out, min_salin_out, salt_loss_out, & - Tliquidus_max_out, & + saltmax_out, phi_init_out, min_salin_out, Tliquidus_max_out, & min_bgc_out, dSin0_frazil_out, hi_ssl_out, hs_ssl_out, hs_ssl_min_out, & awtvdr_out, awtidr_out, awtvdf_out, awtidf_out, cpl_frazil_out, & qqqice_out, TTTice_out, qqqocn_out, TTTocn_out, update_ocn_f_out, & Lfresh_out, cprho_out, Cp_out, ustar_min_out, hi_min_out, a_rapid_mode_out, & - ktherm_out, conduct_out, fbot_xfer_type_out, calc_Tsfc_out, dts_b_out, & + ktherm_out, conduct_out, fbot_xfer_type_out, calc_Tsfc_out, & Rac_rapid_mode_out, aspect_rapid_mode_out, dSdt_slow_mode_out, & - phi_c_slow_mode_out, phi_i_mushy_out, shortwave_out, & - albedo_type_out, albicev_out, albicei_out, albsnowv_out, & + phi_c_slow_mode_out, phi_i_mushy_out, shortwave_out, semi_implicit_Tsfc_out, & + albedo_type_out, albicev_out, albicei_out, albsnowv_out, vapor_flux_correction_out, & albsnowi_out, ahmax_out, R_ice_out, R_pnd_out, R_snw_out, dT_mlt_out, & rsnw_mlt_out, dEdd_algae_out, & kalg_out, R_gC2molC_out, kstrength_out, krdg_partic_out, krdg_redist_out, mu_rdg_out, & atmbndy_out, calc_strair_out, formdrag_out, highfreq_out, natmiter_out, & atmiter_conv_out, calc_dragio_out, & tfrz_option_out, kitd_out, kcatbound_out, hs0_out, frzpnd_out, & - saltflux_option_out, congel_freeze_out, & - floeshape_out, wave_spec_out, wave_spec_type_out, nfreq_out, & + apnd_sl_out, saltflux_option_out, congel_freeze_out, & + floeshape_out, wave_spec_out, wave_spec_type_out, wave_height_type_out, nfreq_out, & dpscale_out, rfracmin_out, rfracmax_out, pndaspect_out, hs1_out, hp1_out, & bgc_flux_type_out, z_tracers_out, scale_bgc_out, solve_zbgc_out, & modal_aero_out, use_macromolecules_out, restartbgc_out, use_atm_dust_iron_out, & - skl_bgc_out, solve_zsal_out, grid_o_out, l_sk_out, & - initbio_frac_out, grid_oS_out, l_skS_out, & + skl_bgc_out, grid_o_out, l_sk_out, initbio_frac_out, & phi_snow_out, conserv_check_out, & fr_resp_out, algal_vel_out, R_dFe2dust_out, dustFe_sol_out, & T_max_out, fsal_out, op_dep_min_out, fr_graze_s_out, fr_graze_e_out, & @@ -1399,6 +1375,7 @@ 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, snwgrain_out, & snwredist_out, use_smliq_pnd_out, rsnw_fall_out, rsnw_tmax_out, & + snw_growth_wet_out, drsnw_min_out, snwliq_max_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, & @@ -1498,7 +1475,6 @@ icepack_query_parameters saltmax_out, & ! max salinity at ice base for BL99 (ppt) phi_init_out, & ! initial liquid fraction of frazil min_salin_out, & ! threshold for brine pocket treatment - salt_loss_out, & ! fraction of salt retained in zsalinity Tliquidus_max_out, & ! maximum liquidus temperature of mush (C) dSin0_frazil_out ! bulk salinity reduction of newly formed frazil @@ -1517,10 +1493,12 @@ icepack_query_parameters calc_Tsfc_out ,&! if true, calculate surface temperature ! if false, Tsfc is computed elsewhere and ! atmos-ice fluxes are provided to CICE + semi_implicit_Tsfc_out ,&! compute dfsurf/dT, dflat/dT terms instead of fsurf, flat + vapor_flux_correction_out ,&! compute mass/enthalpy correction when evaporation/sublimation + ! computed outside at 0C update_ocn_f_out ! include fresh water and salt fluxes for frazil real (kind=dbl_kind), intent(out), optional :: & - dts_b_out, & ! zsalinity timestep hi_min_out, & ! minimum ice thickness allowed (m) for thermo ustar_min_out ! minimum friction velocity for ice-ocean heat flux @@ -1605,14 +1583,16 @@ icepack_query_parameters !----------------------------------------------------------------------- real(kind=dbl_kind), intent(out), optional :: & - Cf_out, & ! ratio of ridging work to PE change in ridging - Pstar_out, & ! constant in Hibler strength formula - Cstar_out, & ! constant in Hibler strength formula - dragio_out, & ! ice-ocn drag coefficient + itd_area_min_out, & ! zap residual ice below this minimum area + itd_mass_min_out, & ! zap residual ice below this minimum mass + Cf_out, & ! ratio of ridging work to PE change in ridging + Pstar_out, & ! constant in Hibler strength formula + Cstar_out, & ! constant in Hibler strength formula + dragio_out, & ! ice-ocn drag coefficient thickness_ocn_layer1_out, & ! thickness of first ocean level (m) - iceruf_ocn_out, & ! under-ice roughness (m) - gravit_out, & ! gravitational acceleration (m/s^2) - iceruf_out ! ice surface roughness (m) + iceruf_ocn_out, & ! under-ice roughness (m) + gravit_out, & ! gravitational acceleration (m/s^2) + iceruf_out ! ice surface roughness (m) integer (kind=int_kind), intent(out), optional :: & ! defined in namelist kstrength_out , & ! 0 for simple Hibler (1979) formulation @@ -1684,7 +1664,8 @@ icepack_query_parameters wave_spec_out ! if true, use wave forcing character (len=*), intent(out), optional :: & - wave_spec_type_out ! type of wave spectrum forcing + wave_spec_type_out, & !type of wave spectrum forcing + wave_height_type_out ! type of wave height forcing !----------------------------------------------------------------------- ! Parameters for biogeochemistry @@ -1707,20 +1688,15 @@ icepack_query_parameters conserv_check_out ! if .true., run conservation checks and abort if checks fail logical (kind=log_kind), intent(out), optional :: & - skl_bgc_out, & ! if true, solve skeletal biochemistry - solve_zsal_out ! if true, update salinity profile from solve_S_dt + skl_bgc_out ! if true, solve skeletal biochemistry real (kind=dbl_kind), intent(out), optional :: & grid_o_out , & ! for bottom flux - l_sk_out , & ! characteristic diffusive scale (zsalinity) (m) + l_sk_out , & ! characteristic diffusive scale (m) grid_o_t_out , & ! top grid point length scale initbio_frac_out, & ! fraction of ocean tracer concentration used to initialize tracer phi_snow_out ! snow porosity at the ice/snow interface - real (kind=dbl_kind), intent(out), optional :: & - grid_oS_out , & ! for bottom flux (zsalinity) - l_skS_out ! 0.02 characteristic skeletal layer thickness (m) (zsalinity) - real (kind=dbl_kind), intent(out), optional :: & ratio_Si2N_diatoms_out, & ! algal Si to N (mol/mol) ratio_Si2N_sp_out , & @@ -1854,7 +1830,7 @@ icepack_query_parameters real (kind=dbl_kind), intent(out), optional :: & hs0_out ! snow depth for transition to bare sea ice (m) - ! level-ice ponds + ! level-ice and sealvl ponds character (len=*), intent(out), optional :: & frzpnd_out ! pond refreezing parameterization @@ -1865,6 +1841,10 @@ icepack_query_parameters pndaspect_out, & ! ratio of pond depth to pond fraction hs1_out ! tapering parameter for snow on pond ice + ! sealvl ponds + real (kind=dbl_kind), intent(out), optional :: & + apnd_sl_out ! equilibrium pond fraction for sea level parameterization + ! topo ponds real (kind=dbl_kind), intent(out), optional :: & hp1_out ! critical parameter for pond ice thickness @@ -1889,7 +1869,10 @@ 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 + snw_growth_wet_out,&! wet metamorphism parameter (um^3/s) + drsnw_min_out, & ! minimum snow grain growth factor + snwliq_max_out ! irreducible saturation fraction integer (kind=int_kind), intent(out), optional :: & isnw_T_out, & ! maxiumum temperature index @@ -2043,6 +2026,8 @@ icepack_step_radiation yday, sec, & swvdr, swvdf, & swidr, swidf, & + swuvrdr, swuvrdf, & + swpardr, swpardf, & coszen, fsnow, & alvdrn, alvdfn, & alidrn, alidfn, & @@ -2052,6 +2037,10 @@ icepack_step_radiation fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswpenln, & Sswabsn, Iswabsn, & albicen, albsnon, & @@ -2071,6 +2060,12 @@ icepack_step_radiation fsnow , & ! snowfall rate (kg/m^2 s) TLAT, TLON ! latitude and longitude (radian) + real (kind=dbl_kind), intent(in), optional :: & + swuvrdr , & ! sw down, uv dir (W/m^2) + swuvrdf , & ! sw down, uv dif (W/m^2) + swpardr , & ! sw down, par dir (W/m^2) + swpardf ! sw down, par dif (W/m^2) + integer (kind=int_kind), intent(in) :: & sec ! elapsed seconds into date @@ -2078,7 +2073,7 @@ icepack_step_radiation yday ! day of the year character (len=char_len), intent(in), optional :: & - calendar_type ! differentiates Gregorian from other calendars + calendar_type ! differentiates proleptic_gregorian from other calendars integer (kind=int_kind), intent(in), optional :: & days_per_year ! number of days in one year @@ -2129,7 +2124,11 @@ icepack_step_radiation fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) + fswthrun_uvrdr,& ! uv dir SW through ice to ocean (W/m^2) + fswthrun_uvrdf,& ! uv dif SW through ice to ocean (W/m^2) + fswthrun_pardr,& ! par dir SW through ice to ocean (W/m^2) + fswthrun_pardf ! par dif SW through ice to ocean (W/m^2) real (kind=dbl_kind), dimension(:,:), intent(inout) :: & fswpenln , & ! visible SW entering ice layers (W m-2) @@ -2253,7 +2252,7 @@ icepack_step_therm2 fresh, fsalt, & fhocn, update_ocn_f, & faero_ocn, & - first_ice, fzsal, & + first_ice, & flux_bio, ocean_bio, & frazil_diag, & frz_onset, yday, & @@ -2262,9 +2261,9 @@ icepack_step_therm2 wave_sig_ht, & wave_spectrum, & wavefreq, & - dwavefreq, & d_afsd_latg, d_afsd_newi, & - d_afsd_latm, d_afsd_weld) + d_afsd_latm, d_afsd_weld, & + dpnd_melt) use icepack_parameters, only: icepack_init_parameters @@ -2309,7 +2308,7 @@ icepack_step_therm2 frazil_diag ! frazil ice growth diagnostic (m/step-->cm/day) real (kind=dbl_kind), intent(inout), optional :: & - fzsal ! salt flux to ocean from zsalinity (kg/m^2/s) (deprecated) + dpnd_melt ! pond 'drainage' due to ice melting (m / step) real (kind=dbl_kind), intent(in), optional :: & wlat ! lateral melt rate (m/s) @@ -2351,8 +2350,7 @@ icepack_step_therm2 wave_spectrum ! ocean surface wave spectrum E(f) (m^2 s) real(kind=dbl_kind), dimension(:), intent(in), optional :: & - wavefreq, & ! wave frequencies (s^-1) - dwavefreq ! wave frequency bin widths (s^-1) + wavefreq ! wave frequencies (s^-1) real (kind=dbl_kind), dimension(:), intent(out), optional :: & ! change in floe size distribution (area) @@ -2563,6 +2561,10 @@ icepack_step_therm1 fswthrun_vdf, & fswthrun_idr, & fswthrun_idf, & + fswthrun_uvrdr, & + fswthrun_uvrdf, & + fswthrun_pardr, & + fswthrun_pardf, & fswabs , & flwout , & Sswabsn , Iswabsn , & @@ -2578,8 +2580,13 @@ icepack_step_therm1 fswthru_vdf , & fswthru_idr , & fswthru_idf , & + fswthru_uvrdr , & + fswthru_uvrdf , & + fswthru_pardr , & + fswthru_pardf , & flatn_f , fsensn_f , & fsurfn_f , fcondtopn_f , & + dfsurfdT , dflatdT , & faero_atm , faero_ocn , & fiso_atm , fiso_ocn , & fiso_evap , & @@ -2598,7 +2605,12 @@ icepack_step_therm1 lmask_n , lmask_s , & mlt_onset , frz_onset , & yday , prescribed_ice, & - zlvs , afsdn) + zlvs , afsdn , & + dpnd_flush , dpnd_flushn , & + dpnd_expon , dpnd_exponn , & + dpnd_freebd , dpnd_freebdn, & + dpnd_initial, dpnd_initialn, & + dpnd_dlid , dpnd_dlidn) real (kind=dbl_kind), intent(in) :: & dt , & ! time step @@ -2685,6 +2697,13 @@ icepack_step_therm1 mlt_onset , & ! day of year that sfc melting begins frz_onset ! day of year that freezing begins (congel or frazil) + real (kind=dbl_kind), intent(inout), optional :: & + dpnd_flush , & ! pond flushing rate due to ice permeability (m/step) + dpnd_expon , & ! exponential pond drainage rate (m/step) + dpnd_freebd , & ! pond drainage rate due freeboard constraint (m/step) + dpnd_initial, & ! runoff rate due to rfrac (m/step) + dpnd_dlid ! pond loss/gain (+/-) to ice lid (m/step) + real (kind=dbl_kind), intent(out), optional :: & wlat ! lateral melt rate (m/s) @@ -2693,6 +2712,10 @@ icepack_step_therm1 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_uvrdr,& ! uv dir shortwave penetrating to ocean (W/m^2) + fswthru_uvrdf,& ! uv dif shortwave penetrating to ocean (W/m^2) + fswthru_pardr,& ! par dir shortwave penetrating to ocean (W/m^2) + fswthru_pardf,& ! par dif shortwave penetrating to ocean (W/m^2) dsnow , & ! change in snow depth (m/step-->cm/day) fsloss ! rate of snow loss to leads (kg/m^2/s) @@ -2733,7 +2756,7 @@ icepack_step_therm1 Tsfc , & ! ice/snow surface temperature, Tsfcn alvl , & ! level ice area fraction vlvl , & ! level ice volume fraction - apnd , & ! melt pond area fraction + apnd , & ! melt pond area fraction tracer hpnd , & ! melt pond depth (m) ipnd , & ! melt pond refrozen lid thickness (m) iage , & ! volume-weighted ice age @@ -2760,6 +2783,13 @@ icepack_step_therm1 congeln , & ! congelation ice growth (m) snoicen ! snow-ice growth (m) + real (kind=dbl_kind), dimension(:), intent(inout), optional :: & + dpnd_flushn , & ! category pond flushing rate (m/step) + dpnd_exponn , & ! exponential pond drainage rate (m/step) + dpnd_freebdn, & ! pond drainage rate due to freeboard (m/step) + dpnd_initialn,& ! runoff rate due to rfrac (m/step) + dpnd_dlidn ! category pond loss/gain due to ice lid (m/step) + real (kind=dbl_kind), dimension(:), intent(in) :: & fswthrun ! SW through ice to ocean (W/m^2) @@ -2767,10 +2797,16 @@ icepack_step_therm1 dsnown ! change in snow thickness (m/step-->cm/day) real (kind=dbl_kind), dimension(:), intent(in), optional :: & + dfsurfdT , & ! derivative of fsurfn with respect to temperatur (W m-2 K-1) + dflatdT , & ! derivative of flatn with respect to temperature (W m-2 K-1) fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) - fswthrun_idf ! nir dif SW through ice to ocean (W/m^2) + fswthrun_idf , & ! nir dif SW through ice to ocean (W/m^2) + fswthrun_uvrdr,& ! uv dir SW through ice to ocean (W/m^2) + fswthrun_uvrdf,& ! uv dif SW through ice to ocean (W/m^2) + fswthrun_pardr,& ! par dir SW through ice to ocean (W/m^2) + fswthrun_pardf ! par dif SW through ice to ocean (W/m^2) real (kind=dbl_kind), dimension(:,:), intent(inout) :: & zqsn , & ! snow layer enthalpy (J m-3) @@ -2801,7 +2837,7 @@ icepack_init_tracer_flags subroutine icepack_init_tracer_flags(& tr_iage_in, tr_FY_in, tr_lvl_in, tr_snow_in, & - tr_pond_in, tr_pond_lvl_in, tr_pond_topo_in, & + tr_pond_in, tr_pond_lvl_in, tr_pond_topo_in, tr_pond_sealvl_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, & tr_bgc_Am_in, tr_bgc_Sil_in, tr_bgc_DMS_in, tr_bgc_Fe_in, tr_bgc_hum_in, & @@ -2814,6 +2850,7 @@ icepack_init_tracer_flags tr_pond_in , & ! if .true., use melt 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_pond_sealvl_in,& ! if .true., use sealvl pond parameteriztion tr_snow_in , & ! if .true., use snow redistribution or metamorphosis tracers tr_fsd_in , & ! if .true., use floe size distribution tracers tr_iso_in , & ! if .true., use isotope tracers @@ -2844,7 +2881,7 @@ icepack_query_tracer_flags subroutine icepack_query_tracer_flags(& tr_iage_out, tr_FY_out, tr_lvl_out, tr_snow_out, & - tr_pond_out, tr_pond_lvl_out, tr_pond_topo_out, & + tr_pond_out, tr_pond_lvl_out, tr_pond_topo_out, tr_pond_sealvl_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, & tr_bgc_Am_out, tr_bgc_Sil_out, tr_bgc_DMS_out, tr_bgc_Fe_out, tr_bgc_hum_out, & @@ -2857,6 +2894,7 @@ icepack_query_tracer_flags tr_pond_out , & ! if .true., use melt 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_pond_sealvl_out,& ! if .true., use sealvl pond parameterization tr_snow_out , & ! if .true., use snow redistribution or metamorphosis tracers tr_fsd_out , & ! if .true., use floe size distribution tr_iso_out , & ! if .true., use isotope tracers @@ -2913,7 +2951,7 @@ icepack_init_tracer_indices nlt_bgc_DOC_in, nlt_bgc_DON_in, nlt_bgc_DIC_in, nlt_bgc_Fed_in, & nlt_bgc_Fep_in, nlt_bgc_Nit_in, nlt_bgc_Am_in, nlt_bgc_Sil_in, & nlt_bgc_DMSPp_in, nlt_bgc_DMSPd_in, nlt_bgc_DMS_in, nlt_bgc_hum_in, & - nlt_bgc_PON_in, nt_zbgc_frac_in, nt_bgc_S_in, nlt_chl_sw_in, & + nlt_bgc_PON_in, nt_zbgc_frac_in, nlt_chl_sw_in, & nlt_zaero_sw_in, & bio_index_o_in, bio_index_in) @@ -2955,7 +2993,6 @@ icepack_init_tracer_indices nlt_bgc_hum_in,& ! nlt_bgc_PON_in,& ! zooplankton and detritus nt_zbgc_frac_in,&! fraction of tracer in the mobile phase - nt_bgc_S_in, & ! (deprecated, was related to zsalinity) nlt_chl_sw_in ! points to total chla in trcrn_sw integer (kind=int_kind), dimension(:), intent(in), optional :: & @@ -3017,7 +3054,7 @@ icepack_query_tracer_indices nlt_bgc_DOC_out, nlt_bgc_DON_out, nlt_bgc_DIC_out, nlt_bgc_Fed_out, & nlt_bgc_Fep_out, nlt_bgc_Nit_out, nlt_bgc_Am_out, nlt_bgc_Sil_out, & nlt_bgc_DMSPp_out, nlt_bgc_DMSPd_out, nlt_bgc_DMS_out, nlt_bgc_hum_out, & - nlt_bgc_PON_out, nt_zbgc_frac_out, nt_bgc_S_out, nlt_chl_sw_out, & + nlt_bgc_PON_out, nt_zbgc_frac_out, nlt_chl_sw_out, & nlt_zaero_sw_out, & bio_index_o_out, bio_index_out) @@ -3059,7 +3096,6 @@ icepack_query_tracer_indices nlt_bgc_hum_out,& ! nlt_bgc_PON_out,& ! zooplankton and detritus nt_zbgc_frac_out,&! fraction of tracer in the mobile phase - nt_bgc_S_out, & ! (deprecated, was related to zsalinity) nlt_chl_sw_out ! points to total chla in trcrn_sw integer (kind=int_kind), dimension(:), intent(out), optional :: & @@ -3228,7 +3264,7 @@ icepack_compute_tracers trcr_base, n_trcr_strata, & nt_strata, trcrn, Tf) - integer (kind=int_kind), dimension (ntrcr), intent(in) :: & + integer (kind=int_kind), dimension (:), intent(in) :: & trcr_depend, & ! = 0 for aicen tracers, 1 for vicen, 2 for vsnon n_trcr_strata ! number of underlying tracer layers @@ -3247,7 +3283,7 @@ icepack_compute_tracers vicen , & ! volume per unit area of ice (m) vsnon ! volume per unit area of snow (m) - real (kind=dbl_kind), dimension (ntrcr), intent(out) :: & + real (kind=dbl_kind), dimension (:), intent(out) :: & trcrn ! ice tracers real (kind=dbl_kind), intent(in) :: & @@ -3368,15 +3404,11 @@ icepack_step_wavefracture ! ! authors: 2018 Lettie Roach, NIWA/VUW ! - subroutine icepack_step_wavefracture(wave_spec_type, & + subroutine icepack_step_wavefracture( & dt, nfreq, & aice, vice, aicen, & wave_spectrum, wavefreq, dwavefreq, & - trcrn, d_afsd_wave) - - - character (len=char_len), intent(in) :: & - wave_spec_type ! type of wave spectrum forcing + trcrn, d_afsd_wave, wave_height) integer (kind=int_kind), intent(in) :: & nfreq ! number of wave frequency categories @@ -3403,6 +3435,9 @@ icepack_step_wavefracture real (kind=dbl_kind), dimension(:), intent(out) :: & d_afsd_wave ! change in fsd due to waves + real (kind=dbl_kind), intent(in), optional :: & + wave_height ! significant wave height (m) + real (kind=dbl_kind), dimension(nfsd,ncat) :: & d_afsdn_wave ! change in fsd due to waves, per category diff --git a/doc/source/user_guide/lg_overview.rst b/doc/source/user_guide/lg_overview.rst index 0d324361..0ad96e86 100755 --- a/doc/source/user_guide/lg_overview.rst +++ b/doc/source/user_guide/lg_overview.rst @@ -12,9 +12,10 @@ Icepack includes options for simulating sea ice thermodynamics, mechanical redis tracers, including thickness, enthalpy, ice age, first-year ice area, deformed ice area and volume, melt ponds, and biogeochemistry. -Icepack is called on a grid point by grid point basis. All data is passed in and out of the model -via subroutine interfaces. Fortran "use" statements are not encouraged for accessing data inside -the Icepack model. +Icepack is called on a grid point by grid point basis. All data is passed in and out of the model +via subroutine interfaces. Fortran "use" statements are not encouraged for accessing data inside +the Icepack model from outside. Parameters may be queried and/or reset from Icepack's default +values by calling the query and init interfaces as described in :ref:`sequence_and_interface`. Icepack does not generally contain any parallelization or I/O. The driver of Icepack is expected to support diff --git a/doc/source/user_guide/lg_sequence.rst b/doc/source/user_guide/lg_sequence.rst index 04a72269..1d58229c 100755 --- a/doc/source/user_guide/lg_sequence.rst +++ b/doc/source/user_guide/lg_sequence.rst @@ -126,7 +126,6 @@ computation and a routine to update the radiation computation:: icepack_brine addresses brine computations:: use icepack_brine, only: icepack_init_hbrine - use icepack_brine, only: icepack_init_zsalinity ! DEPRECATED icepack_zbgc contains several public interfaces to support initialization and computation for the skeletal layer bgc and zbgc options:: diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 519ca16a..256a8289 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -97,7 +97,6 @@ can be modified as needed. "NTRAERO", "integer", "number of aerosol tracers", "1" "NTRISO", "integer", "number of water isotope tracers", "1" "TRBRI", "0,1", "brine height tracer", "0" - "TRZS", "", "DEPRECATED", "" "TRBGCS", "0,1", "skeletal layer tracer, needs TRBGCZ=0", "0" "TRBGCZ", "0,1", "zbgc tracers, needs TRBGCS=0 and TRBRI=1", "0" "NBGCLYR", "integer", "number of zbgc layers", "1" @@ -142,12 +141,18 @@ setup_nml "", "``y``", "write restart every ``dumpfreq_n`` years", "" "``dump_last``", "true/false", "write restart at end of run", "false" "``dt``", "seconds", "thermodynamics time step length", "3600." + "``hbar_init_itd``", "real", "initial modal ice thickness for itd-initialized grid cell in m", "3.0" + "``hi_init_slab``", "real", "initial ice thickness for slab-initialized grid cell in m", "2.0" "``history_format``", "``cdf``", "history file output in netcdf format", "``none``" "","``none``","no history output","" + "``hsno_init_itd``", "real", "initial snow depth for itd-initialized grid cell in m", "0.25" + "``hsno_init_slab``", "real", "initial snow depth for slab-initialized grid cell in m", "0.0" "``ice_ic``", "``default``", "latitude and sst dependent initial condition", "``default``" "", "``none``", "no ice", "" "", "'path/file'", "restart file name", "" "``istep0``", "integer", "initial time step number", "0" + "``itd_area_min``", "real", "area below which ice is zapped", "1.e-11" + "``itd_mass_min``", "real", "mass below which ice is zapped", "1.e-10" "``ndtd``", "integer", "number of dynamics/advection/ridging/steps per thermo timestep", "1" "``npt``", "integer", "total number of time steps to take", "99999" "``restart``", "logical", "initialize using restart file", "``.false.``" @@ -155,6 +160,7 @@ setup_nml "``restart_file``", "string", "output file prefix for restart dump", "'iced'" "``restart_format``", "``bin``", "restart file output in binary format", "``bin``" "","``cdf``","restart file output in netcdf format","" + "``sst_init``", "real", "initial ocean mixed layer temperature in C", "-1.8" "``use_leap_years``", "logical", "include leap days", "``.false.``" "``year_init``", "integer", "the initial year if not using restart", "0" "", "", "", "" @@ -190,6 +196,7 @@ tracer_nml "``tr_lvl``", "logical", "level ice area and volume", "``.false.``" "``tr_pond_lvl``", "logical", "level-ice melt ponds", "``.false.``" "``tr_pond_topo``", "logical", "topo melt ponds", "``.false.``" + "``tr_pond_sealvl``", "logical", "sealvl melt ponds", "``.false.``" "``tr_snow``", "logical", "advanced snow physics", "``.false.``" "", "", "", "" @@ -287,6 +294,7 @@ ponds_nml "``hs0``", "real", "snow depth of transition to bare sea ice in m", "0.03" "``hs1``", "real", "snow depth of transition to pond ice in m", "0.03" "``pndaspect``", "real", "aspect ratio of pond changes (depth:area)", "0.8" + "``apnd_sl``", "real", "equilibrium pond fraction for sealvl ponds", "0.27" "``rfracmax``", ":math:`0 \le r_{max} \le 1`", "maximum melt water added to ponds", "0.85" "``rfracmin``", ":math:`0 \le r_{min} \le 1`", "minimum melt water added to ponds", "0.15" "", "", "", "" @@ -331,10 +339,12 @@ forcing_nml "``atmiter_conv``", "real", "convergence criteria for ustar", "0.0" "``atm_data_file``", "string", "file containing atmospheric data", "' '" "``atm_data_format``", "``bin``", "read direct access binary forcing files", "``bin``" + "", "``nc``", "read netCDF forcing files", "" "``atm_data_type``", "``clim``", "monthly climatology (see :ref:`force`)", "``default``" "", "``CFS``", "CFS model output (see :ref:`force`)", "" "", "``default``", "constant values defined in the code", "" "", "``ISPOL``", "ISPOL experiment data (see :ref:`force`)", "" + "", "``MDF``", "Merged Data File (MDF) formatted forcing data (see :ref:`init`)", "" "", "``NICE``", "N-ICE experiment data (see :ref:`force`)", "" "``bgc_data_file``", "string", "file containing biogeochemistry data", "' '" "``bgc_data_format``", "``bin``", "read direct access binary forcing files", "``bin``" @@ -358,6 +368,7 @@ forcing_nml "``formdrag``", "logical", "calculate form drag", "``.false.``" "``fyear_init``", "integer", "first year of atmospheric forcing data", "1998" "``highfreq``", "logical", "high-frequency atmo coupling", "``.false.``" + "``hmix_fixed``", "real", "constant ocean mixed layer depth in m", "20.0" "``lateral_flux_type``", "``uniform_ice``", "flux ice with identical properties into the cell when closing (Icepack only)", "" "", "``none``", "advect open water into the cell when closing (Icepack only)", "" "``ice_data_file``", "string", "file containing ice opening, closing data", "' '" @@ -367,17 +378,23 @@ forcing_nml "``oceanmixed_ice``", "logical", "active ocean mixed layer calculation", "``.false.``" "``ocn_data_file``", "string", "file containing ocean data", "' ' " "``ocn_data_format``", "``bin``", "read direct access binary forcing files", "``bin``" + "", "``nc``", "read netCDF forcing files", "" "``ocn_data_type``", "``default``", "constant values defined in the code", "``default``" "", "``ISPOL``", "ISPOL experiment data (see :ref:`force`)", "" + "", "``MDF``", "Merged Data File (MDF) formatted forcing data (see :ref:`init`)", "" "", "``NICE``", "N-ICE experiment data (see :ref:`force`)", "" "", "``SHEBA``", "Opening/closing dataset from SHEBA", "" + "``precalc_forc``", "logical", "average/interpolate forcing data on initialization", "``.false.``" "``precip_units``", "``mks``", "liquid precipitation data units", "``mks``" "", "``mm_per_month``", "", "" "", "``mm_per_sec``", "(same as MKS units)", "" "", "``m_per_sec``", "", "" + "``qdp_fixed``", "real", "constant oceanic heat flux convergence W/m^2", "0.0" "``restore_ocn``", "logical", "restore sst to data", "``.false.``" "``saltflux_option``", "``constant``","salt flux is referenced to a constant salinity","``constant``" "","``prognostic``","use actual sea ice bulk salinity in flux" + "``semi-implicit_Tsfc``", "logical", "surface temperature coupling option based on d(hf)/dTs", "``.false.``" + "``sss_fixed``", "real", "constant ocean mixed layer salinity in ppt", "34.0" "``tfrz_option``","``constant``", "constant ocean freezing temperature (Tocnfrz)","``mushy``" "", "``linear_salt``", "linear function of salinity (ktherm=1)", "" "", "``minus1p8``", "constant ocean freezing temperature (:math:`-1.8^{\circ} C`)", "" @@ -386,6 +403,7 @@ forcing_nml "``update_ocn_f``", "``.false.``", "do not include frazil water/salt fluxes in ocn fluxes", "``.false.``" "", "``true``", "include frazil water/salt fluxes in ocn fluxes", "" "``ustar_min``", "real", "minimum value of ocean friction velocity in m/s", "0.005" + "``vapor_flux_correction``", "logical", "water vapor deposition/sublimation correction associated with an assumed temperature", "``.false.``" "``wave_spec_type``", "``constant``", "wave data file is provided, sea surface height generated using constant phase (1 iteration of wave fracture)", "``none``" "", "``none``", "no wave data provided, no wave-ice interactions (not recommended when using the FSD)", "" "", "``profile``", "no wave data file is provided, use fixed dummy wave spectrum, for testing, sea surface height generated using constant phase (1 iteration of wave fracture)", "" @@ -454,7 +472,6 @@ zbgc_nml "``f_exude_l``", "real", "fraction of exudation to DOC lipids", "1.0" "``f_exude_s``", "real", "fraction of exudation to DOC saccharids", "1.0" "``grid_o``", "real", "z biology length scale for bottom flux (m)", "0.006" - "``grid_oS``", "real", "DEPRECATED", "" "``grow_Tdep_diatoms``", "real", "temperature dependence growth diatoms per degC", "0.063" "``grow_Tdep_phaeo``", "real", "temperature dependence growth phaeocystis per degC", "0.063" "``grow_Tdep_sp``", "real", "temperature dependence growth small plankton per degC", "0.063" @@ -480,7 +497,6 @@ zbgc_nml "``K_Sil_sp``", "real", "silicate half saturation small plankton mmol/m^3", "0.0" "``kn_bac_protein``", "real", "bacterial degradation of DON per day", "0.2" "``l_sk``", "real", "characteristic diffusive scale in m", "2.0" - "``l_skS``", "real", "DEPRECATED", "" "``max_dfe_doc1``", "real", "max ratio of dFe to saccharides in the ice in nm Fe / muM C", "0.2" "``max_loss``", "real", "restrict uptake to percent of remaining value", "0.9" "``modal_aero``", "logical", "modal aerosols", "``.false.``" @@ -524,7 +540,6 @@ zbgc_nml "``silicatetype``", "real", "mobility type between stationary and mobile silicate", "-1.0" "``skl_bgc``", "logical", "DEPRECATED: skeletal layer biogeochemistry", "``.false.``" "``solve_zbgc``", "logical", "solve z-biogeochemistry reactions", "``.false.``" - "``solve_zsal``", "logical", "DEPRECATED", "``.false.``" "``tau_max``", "real", "long time mobile to stationary exchanges (s)", "604800.0" "``tau_min``", "real", "rapid module to stationary exchanges (s)", "3600.0" "``tr_bgc_Am``", "logical", "ammonium tracer", "``.false.``" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index 76a0db32..bce94095 100755 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -28,6 +28,9 @@ source code for the driver, and the scripts. Forcing data is available from the The directory structure of Icepack is as follows. All columnphysics filename have a prefix of icepack\_ and all driver files are prefixed with icedrv\_*. +**COPYRIGHT.pdf** + copyright notice + **LICENSE.pdf** license for using and sharing the code @@ -118,17 +121,74 @@ will be described in more detail in the :ref:`tabnamelist`. Two namelist variables control model initialization, ``ice_ic`` and ``restart``. Setting ``ice_ic`` = 'default' causes the model to run using -initial values set in the code. To start +initial values set in the code and the namelist. To start from a file **filename**, set ``restart`` = .true. and ``ice_ic`` = **filename**. When restarting using the Icepack driver, for simplicity the tracers are assumed to be set the same way (on/off) as in the run that created the restart file; i.e. that the restart file contains exactly the information needed for the new run. CICE is more flexible in this regard. +When the model is not running from a restart file (i.e., ``ice_ic`` = 'default' +and ``restart`` = .false.), there are namelist options that control the initial +snow depth , ice thicknesses and mixed layer temperature (``sst_init``). +For the slab-initialized grid cell (``nx`` = 2), the run starts with a single +ice thickness category having 100% ice cover . ``hsno_init_slab`` and +``hi_init_slab`` define the initial snow depth and ice thickness for that +ice thickness category. For the itd-initialized grid cell (``nx`` = 3), the ice +thickness in each category is set to the midpoint of that category's ice +thickness range (excluding the last category, which is set to 1 m thicker than +the lower bound). The area fraction of each category is set according to a +normalized, downward-facing parabolic function of ice thickness, where the +maximum of the parabola is ``hbar_init_itd`` and the area fraction of open +water is zero. All thickness categories are initialized with a snow depth of +``hsno_init_itd``. + For stand-alone runs, -routines in **icedrv\_forcing.F90** read and interpolate data from files, -and are intended merely for testing, although they can also provide guidance for -the user to write his or her own routines. +routines in **icedrv\_forcing.F90** read and interpolate data from files. +The namelist variables ``precalc_forc``, ``atm_data_type``, +``atm_data_format``, ``ocn_data_type``, and ``ocn_data_format`` control +how the forcing data is handled. If ``precalc_forc`` = .false. and the +``atm/ocn_data_type`` = 'bin', when ``init_forcing`` is called, a +subroutine for the specific dataset (e.g., ``atm_CFS``) stores the +forcing data in the ``*_data`` arrays in essentially the same format +that the raw data is present in, without timestamp information. Then, +at each timestep the ``get_forcing`` subroutine has a code block for +each forcing dataset that contains the forcing's time basis and +interpolates the forcing data to the given timestep. The forcing data +that is available in 'bin' format are intended merely for code testing, +not scientific results. + +If ``precalc_forc`` = .true., ``atm/ocn_data_type`` = 'MDF', and +``atm/ocn_data_format`` = 'nc', then ``init_forcing`` reads data from +netCDF files formatted according to the Merged Data File (MDF) +conventions, which includes timestamp information. During initialization, +the forcing data is averaged/interpolated to the Icepack timestep and +stored the the ``*_data`` arrays. The ``get_forcing`` subroutine then +simply queries the ``*_data`` arrays at each timestep. MDF forcing data +are expected to come from observations, and hence may contain missing +data and may be present at a shorter or longer sampling interval than +the Icepack timestep. To handle variable frequencies and missing data, +forcing data are first temporally-averaged for each timestep and then +interpolated. For a give data variable (``var_data``), The +``MDF_average`` subroutine takes the average of all forcing datapoints +within each ``timestep`` +- 0.5 ``dt`` excluding missing values and +stores the results in ``var_data``. If there is no valid data within +0.5 ``dt`` of a given ``timestep`` (e.g., most timesteps if ``dt`` is +much smaller than the sampling interval) then a missing value is placed +in ``var_data(timestep)``. Then, the ``MDF_interpolate`` subroutine +linearly interpolates missing values in ``var_data``. The MDF +conventions were developed by the Year of Polar Prediction supersite +Model Intercomparison Project (`Uttal et al., 2024 +`_) and a `python toolbox +`_ is available to build MDF +files from raw data. The ``ocn_MDF`` subroutine currently assumes that +the oceanic heat flux convergence (``qdp``) is equal to the turbulent +heat flux over the thermocline. + +If no ocean forcing is provided, namelist variables provide constant +values of the ocean mixed layer salinity (``sss_fixed``), thickness +(``hmix_fixed``), and oceanic heat flux convergence (``qdp_fixed``). If +forcing data is provided then these variables are ignored. .. _parameters: @@ -207,6 +267,9 @@ is done by setting ``ICE_IOTYPE`` to ``netcdf`` in **icepack.settings** or using ``icepack.setup -s`` option ``ionetcdf``. If netCDF is used on a particular machine, the machine env and Macros file must support compilation with netCDF. +Note that some of the ponds history fields are not yet implemented for the topo +ponds option. + .. _bgc-hist: Biogeochemistry History Fields diff --git a/doc/source/user_guide/ug_running.rst b/doc/source/user_guide/ug_running.rst index 782ef56b..1cc5f100 100755 --- a/doc/source/user_guide/ug_running.rst +++ b/doc/source/user_guide/ug_running.rst @@ -390,8 +390,12 @@ On macOS: .. code-block:: bash - # Download the Miniconda installer to ~/Downloads/miniconda.sh + # Check hardware platform (x86_64 or arm64) + uname -m + # Download the compatible Miniconda installer to ~/Downloads/miniconda.sh curl -L https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -o ~/Downloads/miniconda.sh + # or + curl -L https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o ~/Downloads/miniconda.sh # Install Miniconda bash ~/Downloads/miniconda.sh @@ -736,6 +740,46 @@ cases. Current filenames can be found in the options scripts in At present, only the opening and closing rates (1/s) are used from the forcing data. In the namelist, set ``ocn_data_type = SHEBA`` to use this forcing in Icepack. + d) **Multidisciplinary Drifting Observatory for the Study of Arctic Climate (MOSAiC)** + + Atmospheric and oceanic forcing are available from the 2019-2020 Multidisciplinary Drifting Observatory + for the Study of Arctic Climate (MOSAiC) expedition :cite:`Clemens-Sewall25`. The atmospheric forcing is + available minutely and the oceanic forcing is available daily. These data are based on observations from + a collection of drifting ice floes in the Arctic Ocean. MOSAiC consisted of two drift experiments, + in which the R/V Polarstern was moored to a drifting ice floe and continuous observations were made. The + first drift started in October 2019 North of the Laptev Sea (85.4N, 129.2E) and ended in July 2020 in + the Fram Strait (79.2N, 2.6W). The second drift was from August to September, 2020 in the vicinity of + the North Pole (approximately 88.6N, 110.6E). Initial conditions are available for drift 1 in + **set_nml.atmmosaic**. Initial conditions for drift 2 have not yet been implemented in Icepack. + + + Atmospheric forcing fields from :cite:`Clemens-Sewall25` consist of 2-m air temperature (K), 2-m + specific humidity (kg/kg), 2-m wind velocity in the u and v directions (m/s), downward solar radiation + (:math:`W/m^2`), downward longwave radiation (:math:`W/m^2`), and total and solid (snowfall) + precipitation rate (:math:`kg/m^2/s`). Three options are available for the atmospheric forcing for + drift 1. The precip file, `MOSAiC_atm_drift1_precip_MDF_20191015_20200731.nc`, has our best estimate of + the actual precipitation input. The stakes files, `MOSAiC_atm_drift1_stakes_snow_fyi_MDF_20191015_20200731.nc` + and `MOSAiC_atm_drift1_stakes_snow_syi_MDF_20191015_20200731.nc`, contain a pseudo-precipitation that has + been tuned to reproduce the observed snow depth evolution at the manual mass balance ('stakes') sites + on relatively level first-year ice (`_fyi_`) and second-year ice (`_syi_`) respectively. Therefore, the stakes + pseudo-precipitation effectively combines the effects of true precipitation and snow redistribution. + It is recommended to use the precip file for general testing. However, to specifically reproduce the + observed snow depth at the manual mass balance sites with the precip forcing, one would need also need to + accurately reproduce the wind-driven snow redistribution. See :cite:`Raphael24` for further details on the + manual mass balance measurements. + + Oceanic forcing fields consist of mixed layer salinity (PSU), + mixed layer depth (m), turbulent heat fluxes over the halocline and thermocline (:math:`W/m^2`), + mixed layer temperature (K), ocean-ice friction velocity (m/s), and sea ice drift speed (m/s). Note, + Icepack's driver currently lacks a mechanism to use the ocean-ice friction velocity and/or sea ice + drift speed in the thermodynamics calculations. Additionally, caution should be used when using the + modeled ocean mixed layer temperatures. For much of the experiment, Icepack's parameterization + of the ocean mixed layer freezing point differs from the true freezing point by ~0.5 C. + + MOSAiC data are available exclusively as MDF-formatted netCDF files (see :ref:`init`). + + + 3) **Climatological** - Maykut and Untersteiner 1971 :cite:`Maykut71` The climatological forcing consists of a monthly climatology of downward radiative fluxes, air temperature, diff --git a/icepack.setup b/icepack.setup index 788a273c..d6cf6725 100755 --- a/icepack.setup +++ b/icepack.setup @@ -426,6 +426,7 @@ else cp -f ${ICE_SCRIPTS}/tests/report_results.csh ${tsdir} cp -f ${ICE_SCRIPTS}/tests/timeseries.csh ${tsdir} cp -f ${ICE_SCRIPTS}/tests/poll_queue.csh ${tsdir} + cp -f ${ICE_SCRIPTS}/tests/parse_lcov.sh ${tsdir} cat >! ${tsdir}/suite.run << EOF0 #!/bin/csh -f @@ -466,6 +467,21 @@ EOF0 cat >! ${tsdir}/report_codecov.csh << EOF0 #!/bin/csh -f +set useparser = false +if (\$#argv > 0) then + if (\$#argv > 1) then + echo "\${0}: ERROR, -parse is the only optional argument allowed" + exit 3 + else + if ("\$argv[1]" =~ "-parse") then + set useparser = true + else + echo "\${0}: ERROR, -parse is the only optional argument allowed" + exit 3 + endif + endif +endif + source ${ICE_SCRIPTS}/machines/env.${machcomp} set rn0 = "${sdate}-${stime}:${shhash}:${testsuitecnt}:${testsuite}" @@ -903,7 +919,7 @@ cp ${rundir}/compile/*.{gcno,gcda} ${testname_base}/codecov_output/ EOF cat >> ${tsdir}/report_lcov.csh << EOF -lcov --gcov-tool gcov -c -d ${rundir}/compile -o ${testname_base}/lcov.info +lcov --gcov-tool gcov -c --rc geninfo_unexecuted_blocks=1 -d ${rundir}/compile -o ${testname_base}/lcov.info if (-s ${testname_base}/lcov.info) then set lcovalist = "\${lcovalist} -a ${testname_base}/lcov.info" endif @@ -917,7 +933,7 @@ echo "${testname_base}" cd ${testname_base} source ./icepack.settings set md5chk = \`where md5sum\` -if ("\${md5chk}" != "") then +if ("\${md5chk}" != "" && "${coverage}" == "0") then set md5file = icepack.settings.md5 grep -v " ICE_CASENAME " icepack.settings | grep -v " ICE_CASEDIR " | grep -v " ICE_RUNDIR " | grep -v " ICE_TESTNAME " | grep -v " ICE_TEST " >! \${md5file} set icepsetmd5 = \` md5sum \${md5file} | cut -d " " -f 1 \` @@ -987,6 +1003,7 @@ EOF0 if ($coverage == 1) then echo "Generating coverage reports" ./poll_queue.csh +# ./report_lcov.csh -parse ./report_lcov.csh # ./report_codecov.csh endif