From 246b7f5d03355a49adbe152245beaea10030a469 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Wed, 11 Oct 2023 17:00:31 -0500 Subject: [PATCH 001/388] Adds mpas interface for icepack bgc Needs to be tested and merged with main icepack-integration branch BFB in the physics. --- .../namelist_defaults_mpassi.xml | 12 +- components/mpas-seaice/driver/ice_comp_mct.F | 107 +- components/mpas-seaice/src/Registry.xml | 12 +- .../mpas-seaice/src/column/ice_algae.F90 | 5 +- .../mpas-seaice/src/column/ice_colpkg.F90 | 1 + .../mpas_seaice_core_interface.F | 8 +- .../src/shared/mpas_seaice_column.F | 95 +- .../src/shared/mpas_seaice_icepack.F | 1191 ++++++++--------- .../src/shared/mpas_seaice_initialize.F | 6 +- 9 files changed, 711 insertions(+), 726 deletions(-) diff --git a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml index 735be1ce8e1..fe88816d271 100644 --- a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml +++ b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml @@ -317,12 +317,12 @@ 0.0 0.0 0.5 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 +-1.0 +-1.0 +-1.0 +-1.0 +-1.0 +-1.0 7.0 7.0 7.0 diff --git a/components/mpas-seaice/driver/ice_comp_mct.F b/components/mpas-seaice/driver/ice_comp_mct.F index 8649380aad8..3385fa0c37d 100644 --- a/components/mpas-seaice/driver/ice_comp_mct.F +++ b/components/mpas-seaice/driver/ice_comp_mct.F @@ -1909,6 +1909,7 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_config(configs, "config_use_aerosols", config_use_aerosols) call mpas_pool_get_config(configs, "config_use_modal_aerosols", config_use_modal_aerosols) call mpas_pool_get_config(configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call mpas_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) call mpas_pool_get_subpool(block_ptr % structs, 'mesh', meshPool) call mpas_pool_get_subpool(block_ptr % structs, 'ocean_coupling', oceanCoupling) @@ -1947,9 +1948,13 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_array(aerosols, "atmosAerosolFlux", atmosAerosolFlux) endif + call mpas_pool_get_subpool(block_ptr % structs, 'biogeochemistry', biogeochemistry) + if (config_use_zaerosols) then + call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) + call mpas_pool_get_array(biogeochemistry, 'atmosBlackCarbonFlux', atmosBlackCarbonFlux) + call mpas_pool_get_array(biogeochemistry, 'atmosDustFlux', atmosDustFlux) + endif if (config_use_column_biogeochemistry) then - call mpas_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) - call mpas_pool_get_subpool(block_ptr % structs, 'biogeochemistry', biogeochemistry) call mpas_pool_get_array(biogeochemistry, 'oceanAlgaeConc', oceanAlgaeConc) call mpas_pool_get_array(biogeochemistry, 'oceanDOCConc', oceanDOCConc) @@ -1963,15 +1968,10 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_array(biogeochemistry, 'oceanHumicsConc', oceanHumicsConc) call mpas_pool_get_array(biogeochemistry, 'oceanParticulateIronConc', oceanParticulateIronConc) call mpas_pool_get_array(biogeochemistry, 'oceanDissolvedIronConc', oceanDissolvedIronConc) - call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioAlgae', carbonToNitrogenRatioAlgae) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioDON', carbonToNitrogenRatioDON) call mpas_pool_get_array(biogeochemistry, 'DOCPoolFractions', DOCPoolFractions) - if (config_use_zaerosols) then - call mpas_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) - call mpas_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) - endif endif do i = 1, nCellsSolve @@ -2060,6 +2060,42 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ endif endif + ! set aerosols, if configured + if (config_use_zaerosols) then + oceanZAerosolConc(1,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer1, n) + oceanZAerosolConc(2,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer2, n) + oceanZAerosolConc(3,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer3, n) + oceanZAerosolConc(4,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer4, n) + oceanZAerosolConc(5,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer5, n) + oceanZAerosolConc(6,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer6, n) + if (config_use_modal_aerosols) then + atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) & + + x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) + atmosBlackCarbonFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_bcphiwet, n) + !combine wet and dry dust + atmosDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) + atmosDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) + atmosDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) + atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) + else + atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) + atmosBlackCarbonFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) & + + x2i_i % rAttr(index_x2i_Faxa_bcphiwet, n) + ! combine wet and dry dust + atmosDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) + atmosDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) + atmosDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) + atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & + + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) + endif + endif ! import biogeochemistry fields, if configured if (config_use_column_biogeochemistry) then oceanAlgaeConc(1,i) = x2i_i % rAttr(index_x2i_So_algae1, n) @@ -2081,42 +2117,6 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ oceanParticulateIronConc(2,i) = x2i_i % rAttr(index_x2i_So_fep2, n) oceanDissolvedIronConc(1,i) = x2i_i % rAttr(index_x2i_So_fed1, n) oceanDissolvedIronConc(2,i) = x2i_i % rAttr(index_x2i_So_fed2, n) - oceanZAerosolConc(1,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer1, n) - oceanZAerosolConc(2,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer2, n) - oceanZAerosolConc(3,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer3, n) - oceanZAerosolConc(4,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer4, n) - oceanZAerosolConc(5,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer5, n) - oceanZAerosolConc(6,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer6, n) - ! set aerosols, if configured - if (config_use_zaerosols) then - if (config_use_modal_aerosols) then - atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) & - + x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) - atmosBlackCarbonFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_bcphiwet, n) - ! combine wet and dry dust - atmosDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) - atmosDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) - atmosDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) - atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) - else - atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) - atmosBlackCarbonFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) & - + x2i_i % rAttr(index_x2i_Faxa_bcphiwet, n) - ! combine wet and dry dust - atmosDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) - atmosDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) - atmosDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) - atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & - + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) - endif - endif endif end do @@ -2179,6 +2179,11 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_field(aerosols, "atmosAerosolFlux", atmosAerosolFluxField) endif + if (config_use_zaerosols) then + call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) + call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) + endif if (config_use_column_biogeochemistry) then call mpas_pool_get_subpool(domain % blocklist % structs, 'biogeochemistry', biogeochemistry) @@ -2194,11 +2199,6 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_field(biogeochemistry, 'oceanHumicsConc', oceanHumicsConcField) call mpas_pool_get_field(biogeochemistry, 'oceanParticulateIronConc', oceanParticulateIronConcField) call mpas_pool_get_field(biogeochemistry, 'oceanDissolvedIronConc', oceanDissolvedIronConcField) - call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) - if (config_use_zaerosols) then - call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) - call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) - endif endif call mpas_dmpar_exch_halo_field(seaSurfaceTemperatureField) @@ -2229,7 +2229,11 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ if (config_use_aerosols) then call mpas_dmpar_exch_halo_field(atmosAerosolFluxField) endif - + if (config_use_zaerosols) then + call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) + call mpas_dmpar_exch_halo_field(atmosDustFluxField) + call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) + endif if (config_use_column_biogeochemistry) then call mpas_dmpar_exch_halo_field(oceanAlgaeConcField) call mpas_dmpar_exch_halo_field(oceanDOCConcField) @@ -2243,11 +2247,6 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_dmpar_exch_halo_field(oceanHumicsConcField) call mpas_dmpar_exch_halo_field(oceanParticulateIronConcField) call mpas_dmpar_exch_halo_field(oceanDissolvedIronConcField) - call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) - if (config_use_zaerosols) then - call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) - call mpas_dmpar_exch_halo_field(atmosDustFluxField) - endif endif ! REVISION HISTORY: diff --git a/components/mpas-seaice/src/Registry.xml b/components/mpas-seaice/src/Registry.xml index c99741fe66a..c424b92c718 100644 --- a/components/mpas-seaice/src/Registry.xml +++ b/components/mpas-seaice/src/Registry.xml @@ -1414,32 +1414,32 @@ possible_values="-1 = entirely in the mobile phase; 0 = retention dominated; 1 = release dominated; 0.5 = equal but rapid exchange; 2 = equal but slow exchange" icepack_name="feptype_1" /> - - - - - - domain % blocklist do while (associated(block)) @@ -3206,7 +3214,7 @@ subroutine column_radiation(domain, clock, lInitialization) allocate(aerosolsArray(4*nAerosols,nCategories)) allocate(index_shortwaveAerosol(maxAerosolType)) - if (.not. config_use_column_biogeochemistry) then + if (.not. config_use_zaerosols) then index_shortwaveAerosol(1:maxAerosolType) = 1 else do iAerosol = 1, maxAerosolType @@ -3215,7 +3223,7 @@ subroutine column_radiation(domain, clock, lInitialization) endif setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) !$omp parallel do default(shared) firstprivate(aerosolsArray,index_shortwaveAerosol) & !$omp& private(iCategory,iAerosol,lonCellColumn) @@ -3382,7 +3390,8 @@ subroutine column_ridging(domain) ! configs logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), pointer :: & config_dt @@ -3479,6 +3488,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_config(block % configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_array(velocity_solver, "dynamicsTimeStep", dynamicsTimeStep) @@ -3535,7 +3545,7 @@ subroutine column_ridging(domain) allocate(newlyFormedIceLogical(nCategories)) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) ! code abort abortFlag = .false. @@ -3994,12 +4004,14 @@ subroutine column_biogeochemistry(domain) endif setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) ! code abort abortFlag = .false. abortMessage = "" + atmosBioFluxes(:,:) = 0.0_RKIND + do iCell = 1, nCellsSolve ! newly formed ice do iCategory = 1, nCategories @@ -4041,7 +4053,6 @@ subroutine column_biogeochemistry(domain) atmosDustFlux(iBioTracers,iCell) = 1.e-13_RKIND enddo #endif - atmosBioFluxes(:,:) = 0.0_RKIND if (config_use_zaerosols) then indexj = ciceTracerObject % index_verticalAerosolsConcLayer(1) do iBioTracers = 1, maxBCType @@ -4492,7 +4503,8 @@ subroutine seaice_column_aggregate(domain) ocean_coupling logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), dimension(:), pointer :: & iceAreaCell, & @@ -4527,6 +4539,7 @@ subroutine seaice_column_aggregate(domain) call MPAS_pool_get_subpool(block % structs, "ocean_coupling", ocean_coupling) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) call MPAS_pool_get_dimension(mesh, "nCategories", nCategories) @@ -4544,7 +4557,7 @@ subroutine seaice_column_aggregate(domain) call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) do iCell = 1, nCellsSolve @@ -4691,7 +4704,8 @@ subroutine seaice_column_coupling_prep(domain) logical, pointer :: & config_use_ocean_mixed_layer, & config_include_pond_freshwater_feedback, & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols type(MPAS_pool_type), pointer :: & oceanCoupling, & @@ -4802,6 +4816,7 @@ subroutine seaice_column_coupling_prep(domain) call MPAS_pool_get_config(domain % configs, "config_dt", config_dt) call MPAS_pool_get_config(domain % configs, "config_include_pond_freshwater_feedback", config_include_pond_freshwater_feedback) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis) @@ -4994,10 +5009,12 @@ subroutine seaice_column_coupling_prep(domain) !----------------------------------------------------------------- ! Define ocean biogeochemical flux variables !----------------------------------------------------------------- - if (config_use_column_biogeochemistry) then + + oceanBioFluxesAll(:) = 0.0_RKIND + + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then totalOceanCarbonFlux(iCell) = 0.0_RKIND - oceanBioFluxesAll(:) = 0.0_RKIND oceanAlgaeFlux(:,iCell) = 0.0_RKIND oceanDOCFlux(:,iCell) = 0.0_RKIND oceanDICFlux(:,iCell) = 0.0_RKIND @@ -5108,7 +5125,7 @@ subroutine seaice_column_coupling_prep(domain) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanHumicsFlux(iCell) - endif ! config_use_column_biogeochemistry + endif ! config_use_column_biogeochemistry .or. config_use_zaerosols enddo ! iCell @@ -5156,7 +5173,8 @@ subroutine seaice_column_scale_fluxes(domain) mesh logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), dimension(:), pointer :: & iceAreaCell, & @@ -5216,6 +5234,7 @@ subroutine seaice_column_scale_fluxes(domain) iBioTracers call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) block => domain % blocklist do while (associated(block)) @@ -5308,6 +5327,9 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = albedoVisibleDiffuseCell(iCell) * iceAreaInverse albedoIRDiffuseCell(iCell) = albedoIRDiffuseCell(iCell) * iceAreaInverse + if (config_use_zaerosols) & + oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) * iceAreaInverse + if (config_use_column_biogeochemistry) then oceanNitrateFlux(iCell) = oceanNitrateFlux(iCell) * iceAreaInverse @@ -5317,7 +5339,6 @@ subroutine seaice_column_scale_fluxes(domain) oceanDMSPdFlux(iCell) = oceanDMSPdFlux(iCell) * iceAreaInverse oceanDMSFlux(iCell) = oceanDMSFlux(iCell) * iceAreaInverse oceanHumicsFlux(iCell) = oceanHumicsFlux(iCell) * iceAreaInverse - oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) * iceAreaInverse do iBioTracers = 1, maxAlgaeType oceanAlgaeFlux(iBioTracers,iCell) = oceanAlgaeFlux(iBioTracers,iCell) * iceAreaInverse @@ -5360,6 +5381,9 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = 0.0_RKIND albedoIRDiffuseCell(iCell) = 0.0_RKIND + if (config_use_zaerosols) & + oceanDustIronFlux(iCell) = 0.0_RKIND + if (config_use_column_biogeochemistry) then oceanNitrateFlux(iCell) = 0.0_RKIND @@ -5369,7 +5393,6 @@ subroutine seaice_column_scale_fluxes(domain) oceanDMSPdFlux(iCell) = 0.0_RKIND oceanDMSFlux(iCell) = 0.0_RKIND oceanHumicsFlux(iCell) = 0.0_RKIND - oceanDustIronFlux(iCell) = 0.0_RKIND oceanAlgaeFlux(:,iCell) = 0.0_RKIND oceanDOCFlux(:,iCell) = 0.0_RKIND oceanDICFlux(:,iCell) = 0.0_RKIND @@ -6399,12 +6422,14 @@ subroutine init_column_tracer_object(domain, tracerObject) nZBGCTracers logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nCategories", nCategories) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nZBGCTracers", nZBGCTracers) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) ! get the number of CICE tracers in trcrn call init_column_tracer_object_tracer_number(domain, tracerObject) @@ -6428,7 +6453,7 @@ subroutine init_column_tracer_object(domain, tracerObject) call init_column_tracer_object_ancestor_indices(domain, tracerObject) ! biogeochemistry - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then allocate(tracerObject % index_LayerIndexToDataArray(nZBGCTracers)) allocate(tracerObject % index_LayerIndexToBioIndex(nZBGCTracers)) @@ -6636,7 +6661,7 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject) ! biogeochemistry !----------------------------------------------------------------------- - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then ! save tracer number without bio tracers counted tracerObject % nTracersNotBio = tracerObject % nTracers @@ -10257,11 +10282,11 @@ subroutine check_column_package_configs(domain) endif ! check biogeochemistry flags: - if (.not. config_use_column_biogeochemistry .and. (config_use_brine .or. config_use_vertical_zsalinity .or. & - config_use_vertical_biochemistry .or. config_use_shortwave_bioabsorption .or. config_use_vertical_tracers .or. & + if (.not. config_use_column_biogeochemistry .and. (config_use_vertical_zsalinity .or. & + config_use_vertical_biochemistry .or. & config_use_skeletal_biochemistry .or. config_use_nitrate .or. config_use_carbon .or. config_use_chlorophyll .or. & config_use_ammonium .or. config_use_silicate .or. config_use_DMS .or. config_use_nonreactive .or. config_use_humics .or. & - config_use_DON .or. config_use_iron .or. config_use_modal_aerosols .or. config_use_zaerosols)) then + config_use_DON .or. config_use_iron)) then call mpas_log_write(& "check_column_package_configs: config_use_column_biogeochemistry = false. "//& "All biogeochemistry namelist flags must also be false", & @@ -14775,8 +14800,9 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain) config_use_column_biogeochemistry, & config_use_column_shortwave, & config_use_column_package, & - config_use_vertical_biochemistry, & - config_use_vertical_zsalinity + config_use_vertical_tracers, & + config_use_vertical_zsalinity, & + config_use_zaerosols call MPAS_pool_get_config(domain % blocklist % configs, "config_use_column_package", config_use_column_package) @@ -14787,15 +14813,16 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain) ! biogeochemistry call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) - call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) + call MPAS_pool_get_config(block % configs, "config_use_vertical_tracers", config_use_vertical_tracers) call MPAS_pool_get_config(block % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistryPool) call MPAS_pool_get_subpool(block % structs, "diagnostics_biogeochemistry", diagnostics_biogeochemistryPool) - if (config_use_vertical_biochemistry) then + if (config_use_vertical_tracers) then call MPAS_pool_get_array(biogeochemistryPool, "primaryProduction", primaryProduction) call MPAS_pool_get_array(biogeochemistryPool, "totalChlorophyll", totalChlorophyll) call MPAS_pool_get_array(biogeochemistryPool, "netSpecificAlgalGrowthRate", netSpecificAlgalGrowthRate) @@ -14842,7 +14869,7 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain) call MPAS_pool_get_config(block % configs, "config_use_column_shortwave", config_use_column_shortwave) - if (config_use_column_biogeochemistry .or. config_use_column_shortwave) then + if (config_use_column_biogeochemistry .or. config_use_column_shortwave .or. config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistryPool) call MPAS_pool_get_array(biogeochemistryPool, "bioTracerShortwave", bioTracerShortwave) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 9f039b8bb8a..0b0e2216df4 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -264,10 +264,12 @@ subroutine seaice_init_icepack_physics_package_variables(domain, clock) config_do_restart, & config_use_column_biogeochemistry, & config_use_column_shortwave, & - config_use_column_snow_tracers + config_use_column_snow_tracers, & + config_use_zaerosols call MPAS_pool_get_config(domain % configs, "config_use_column_package", config_use_column_package) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) if (config_use_column_package) then @@ -281,7 +283,7 @@ subroutine seaice_init_icepack_physics_package_variables(domain, clock) call init_column_thermodynamic_profiles(domain) ! initialize biogoechemistry profiles - if (config_use_column_biogeochemistry) & + if (config_use_column_biogeochemistry .or. config_use_zaerosols) & call init_column_biogeochemistry_profiles(domain, ciceTracerObject) ! history variables @@ -1032,7 +1034,8 @@ subroutine seaice_icepack_predynamics_time_integration(domain, clock) config_use_column_biogeochemistry, & config_use_column_itd_thermodynamics, & config_calc_surface_temperature, & - config_use_vertical_tracers + config_use_vertical_tracers, & + config_use_zaerosols real(kind=RKIND), pointer :: & config_dt @@ -1045,6 +1048,7 @@ subroutine seaice_icepack_predynamics_time_integration(domain, clock) call MPAS_pool_get_config(domain % configs, "config_use_column_vertical_thermodynamics", & config_use_column_vertical_thermodynamics) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_config(domain % configs, "config_use_column_itd_thermodynamics", config_use_column_itd_thermodynamics) call MPAS_pool_get_config(domain % configs, "config_calc_surface_temperature", config_calc_surface_temperature) call MPAS_pool_get_config(domain % configs, "config_use_vertical_tracers", config_use_vertical_tracers) @@ -1074,7 +1078,7 @@ subroutine seaice_icepack_predynamics_time_integration(domain, clock) !----------------------------------------------------------------- call mpas_timer_start("Column biogeochemistry") - if (config_use_column_biogeochemistry) & + if (config_use_column_biogeochemistry .or. config_use_zaerosols) & call column_biogeochemistry(domain) call mpas_timer_stop("Column biogeochemistry") @@ -2126,7 +2130,8 @@ subroutine column_itd_thermodynamics(domain, clock) logical, pointer :: & config_update_ocean_fluxes, & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols ! dimensions integer, pointer :: & @@ -2263,6 +2268,7 @@ subroutine column_itd_thermodynamics(domain, clock) call MPAS_pool_get_config(block % configs, "config_dt", config_dt) call MPAS_pool_get_config(block % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) call MPAS_pool_get_dimension(mesh, "nCategories", nCategories) @@ -2348,7 +2354,7 @@ subroutine column_itd_thermodynamics(domain, clock) verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) ! code abort abortFlag = .false. @@ -2926,7 +2932,8 @@ subroutine column_radiation(domain, clock, lInitialization) config_use_shortwave_bioabsorption, & config_use_brine, & config_use_modal_aerosols, & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols character(len=strKIND), pointer :: & config_snow_redistribution_scheme @@ -3049,6 +3056,7 @@ subroutine column_radiation(domain, clock, lInitialization) call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols",config_use_modal_aerosols) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry",config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols",config_use_zaerosols) block => domain % blocklist do while (associated(block)) @@ -3140,28 +3148,31 @@ subroutine column_radiation(domain, clock, lInitialization) allocate(index_shortwaveAerosol(maxAerosolType)) allocate(index_verticalAerosolsConc(maxAerosolType)) allocate(index_algaeConc(nAlgae)) - if (.not. config_use_column_biogeochemistry) then + if (.not. config_use_zaerosols) then index_shortwaveAerosol(1:maxAerosolType) = 1 index_verticalAerosolsConc(1:maxAerosolType) = 1 - index_algaeConc(1:nAlgae) = 1 else do iAerosol = 1, maxAerosolType index_shortwaveAerosol(iAerosol) = ciceTracerObject % index_verticalAerosolsConcShortwave(iAerosol) index_verticalAerosolsConc(iAerosol) = ciceTracerObject % index_verticalAerosolsConc(iAerosol) enddo + endif + if (.not. config_use_column_biogeochemistry) then + index_algaeConc(1:nAlgae) = 1 + else do iBioTracers = 1, nAlgae index_algaeConc(iBioTracers) = ciceTracerObject % index_algaeConc(iBioTracers) enddo endif setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) ! snow grain radius array allocate(snow_grain_radius(nSnowLayers,nCategories)) - !$omp parallel do default(shared) firstprivate(aerosolsArray,index_shortwaveAerosol) & - !$omp& private(iCategory,iAerosol,lonCellColumn) + !$omp parallel do default(shared) firstprivate(aerosolsArray,index_shortwaveAerosol,snow_grain_radius) & + !$omp& private(iCategory,iAerosol,iSnowLayer,lonCellColumn) do iCell = 1, nCellsSolve ! set aerosols array @@ -3177,7 +3188,7 @@ subroutine column_radiation(domain, clock, lInitialization) enddo ! iCategory snow_grain_radius(:,:) = 0.0_RKIND - if (config_use_snow_grain_radius) then + if (config_use_snow_grain_radius) then do iCategory = 1, nCategories do iSnowLayer = 1, nSnowLayers snow_grain_radius(iSnowLayer, iCategory) = snowGrainRadius(iSnowLayer,iCategory,iCell) @@ -3306,7 +3317,8 @@ subroutine column_ridging(domain) ! configs logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), pointer :: & config_dt @@ -3398,6 +3410,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_config(block % configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_array(velocity_solver, "dynamicsTimeStep", dynamicsTimeStep) @@ -3454,7 +3467,7 @@ subroutine column_ridging(domain) allocate(newlyFormedIceLogical(nCategories)) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) do iCell = 1, nCellsSolve @@ -3547,10 +3560,10 @@ end subroutine column_ridging subroutine column_biogeochemistry(domain) - use ice_colpkg, only: & - colpkg_biogeochemistry, & - colpkg_init_OceanConcArray, & - colpkg_clear_warnings + use icepack_intfc, only: & + icepack_biogeochemistry, & + icepack_load_ocean_bio_array, & + icepack_warnings_clear use seaice_constants, only: & seaicePuny @@ -3597,15 +3610,8 @@ subroutine column_biogeochemistry(domain) nDON, & nParticulateIron, & nDissolvedIron, & - nZBGCTracers, & - maxAlgaeType, & - maxDOCType, & - maxDICType, & - maxDONType, & - maxIronType, & maxBCType, & - maxDustType, & - maxAerosolType + maxDustType ! variables @@ -3625,9 +3631,6 @@ subroutine column_biogeochemistry(domain) seaSurfaceSalinity, & seaFreezingTemperature, & snowfallRate, & - zSalinityFlux, & - zSalinityGDFlux, & - oceanMixedLayerDepth, & totalSkeletalAlgae, & oceanNitrateConc, & oceanSilicateConc, & @@ -3652,7 +3655,6 @@ subroutine column_biogeochemistry(domain) totalVerticalBiologyIce, & totalVerticalBiologySnow, & penetratingShortwaveFlux, & - zSalinityIceDensity, & basalIceMeltCategory, & surfaceIceMeltCategory, & congelationCategory, & @@ -3779,13 +3781,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_dimension(mesh, "nDON", nDON) call MPAS_pool_get_dimension(mesh, "nParticulateIron", nParticulateIron) call MPAS_pool_get_dimension(mesh, "nDissolvedIron", nDissolvedIron) - call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers) - call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType) - call MPAS_pool_get_dimension(mesh, "maxDOCType", maxDOCType) - call MPAS_pool_get_dimension(mesh, "maxDICType", maxDICType) - call MPAS_pool_get_dimension(mesh, "maxDONType", maxDONType) - call MPAS_pool_get_dimension(mesh, "maxAerosolType", maxAerosolType) - call MPAS_pool_get_dimension(mesh, "maxIronType", maxIronType) call MPAS_pool_get_dimension(mesh, "maxBCType", maxBCType) call MPAS_pool_get_dimension(mesh, "maxDustType", maxDustType) @@ -3824,9 +3819,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrations", oceanBioConcentrations) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologyIce", totalVerticalBiologyIce) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologySnow", totalVerticalBiologySnow) - call MPAS_pool_get_array(biogeochemistry, "zSalinityIceDensity", zSalinityIceDensity) - call MPAS_pool_get_array(biogeochemistry, "zSalinityFlux", zSalinityFlux) - call MPAS_pool_get_array(biogeochemistry, "zSalinityGDFlux", zSalinityGDFlux) call MPAS_pool_get_array(biogeochemistry, "atmosBioFluxes", atmosBioFluxes) call MPAS_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) @@ -3856,7 +3848,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(ocean_coupling, "seaSurfaceTemperature", seaSurfaceTemperature) call MPAS_pool_get_array(ocean_coupling, "seaSurfaceSalinity", seaSurfaceSalinity) call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature) - call MPAS_pool_get_array(ocean_coupling, "oceanMixedLayerDepth", oceanMixedLayerDepth) call MPAS_pool_get_array(atmos_coupling, "snowfallRate", snowfallRate) @@ -3896,12 +3887,14 @@ subroutine column_biogeochemistry(domain) endif setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) - ! code abort - abortFlag = .false. - abortMessage = "" + atmosBioFluxes(:,:) = 0.0_RKIND + !$omp parallel do default(shared) private(iCategory,iBioTracers,iAlgae, rayleighCriteria, & + !$omp& rayleighCriteriaReal) firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & + !$omp& atmosDustFlux, bioShortwaveFluxCell, newlyFormedIce) + ! do iCell = 1, nCellsSolve ! newly formed ice do iCategory = 1, nCategories @@ -3913,28 +3906,23 @@ subroutine column_biogeochemistry(domain) !update ocean concentrations fields and atmospheric fluxes into allocated array #ifdef coupled - call colpkg_init_OceanConcArray(& - nZBGCTracers, & - maxAlgaeType, & - maxDONType, & - maxDOCType, & - maxDICType, & - maxAerosolType, & - maxIronType, & - oceanNitrateConc(iCell), & - oceanAmmoniumConc(iCell), & - oceanSilicateConc(iCell),& - oceanDMSPConc(iCell), & - oceanDMSConc(iCell), & - oceanAlgaeConc(:,iCell), & - oceanDOCConc(:,iCell), & - oceanDONConc(:,iCell), & - oceanDICConc(:,iCell), & - oceanDissolvedIronConc(:,iCell), & - oceanParticulateIronConc(:,iCell), & - oceanZAerosolConc(:,iCell), & - oceanBioConcentrations(:,iCell), & - oceanHumicsConc(iCell)) + + call icepack_load_ocean_bio_array(& + nit=oceanNitrateConc(iCell), & + amm=oceanAmmoniumConc(iCell), & + sil=oceanSilicateConc(iCell), & + dmsp=oceanDMSPConc(iCell), & + dms=oceanDMSConc(iCell), & + algalN=oceanAlgaeConc(:,iCell), & + doc=oceanDOCConc(:,iCell), & + don=oceanDONConc(:,iCell), & + dic=oceanDICConc(:,iCell), & + fed=oceanDissolvedIronConc(:,iCell), & + fep=oceanParticulateIronConc(:,iCell), & + zaeros=oceanZAerosolConc(:,iCell), & + ocean_bio_all=oceanBioConcentrations(:,iCell), & + hum=oceanHumicsConc(iCell)) + #else do iBioTracers = 1, maxBCType atmosBlackCarbonFlux(iBioTracers,iCell) = 1.e-12_RKIND @@ -3943,7 +3931,6 @@ subroutine column_biogeochemistry(domain) atmosDustFlux(iBioTracers,iCell) = 1.e-13_RKIND enddo #endif - atmosBioFluxes(:,:) = 0.0_RKIND if (config_use_zaerosols) then indexj = ciceTracerObject % index_verticalAerosolsConcLayer(1) do iBioTracers = 1, maxBCType @@ -3959,94 +3946,90 @@ subroutine column_biogeochemistry(domain) oceanBioConcentrationsUsed(iBioTracers) = oceanBioConcentrations(iBioData,iCell) enddo ! iBioTracers - abortFlag = .false. - call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) call seaice_total_carbon_content_category(block,& totalCarbonCatInitial,iceAreaCategoryInitial,iceVolumeCategoryInitial,iCell) - call colpkg_clear_warnings() - call colpkg_biogeochemistry(& - config_dt, & - ciceTracerObject % nTracers, & - ciceTracerObject % nBioTracers, & - netNitrateUptake(iCell), & - netAmmoniumUptake(iCell), & - bioDiffusivity(:,:,iCell), & - bioPermeability(:,:,iCell), & - bioShortwaveFlux(:,:,iCell), & - totalVerticalSalinity(iCell), & - darcyVelocityBio(:,iCell), & - netSpecificAlgalGrowthRate(iCell), & - primaryProduction(iCell), & - netBrineHeight(iCell), & - brineBottomChange(:,iCell), & - brineTopChange(:,iCell), & - verticalNitrogenLosses(:,:,iCell), & - snowIceBioFluxes(:,iCell), & - atmosIceBioFluxes(:,iCell), & - oceanBioConcentrationsUsed(:), & - newlyFormedIceLogical(:), & - shortwaveLayerPenetration(:,:,iCell), & - bioPorosity(:,:,iCell), & - bioTemperature(:,:,iCell), & - totalVerticalBiologyIce(:,iCell), & - totalVerticalBiologySnow(:,iCell), & - totalChlorophyll(iCell), & - penetratingShortwaveFlux(:,iCell), & - rayleighCriteria, & - zSalinityIceDensity(:,iCell), & - zSalinityFlux(iCell), & - zSalinityGDFlux(iCell), & - biologyGrid, & - interfaceBiologyGrid, & - interfaceGrid, & - verticalGrid, & - nBioLayers, & - nIceLayers, & - nSnowLayers, & - nAlgae, & - nzAerosols, & - nCategories, & - nDOC, & - nDIC, & - nDON, & - nDissolvedIron, & - nParticulateIron, & - basalIceMeltCategory(:,iCell), & - surfaceIceMeltCategory(:,iCell), & - congelationCategory(:,iCell), & - snowiceFormationCategory(:,iCell), & - seaSurfaceTemperature(iCell), & - seaSurfaceSalinity(iCell), & - seaFreezingTemperature(iCell), & - snowfallRate(iCell), & - snowMeltCategory(:,iCell), & - oceanMixedLayerDepth(iCell), & - initialSalinityProfile(:,iCell), & - iceThicknessCategoryInitial(:,iCell), & - oceanBioFluxes(:,iCell), & - atmosBioFluxes(:,iCell), & - iceAreaCategoryInitial(:,iCell), & - iceVolumeCategoryInitial(:,iCell), & - iceAreaCategory(1,:,iCell), & - iceVolumeCategory(1,:,iCell), & - snowVolumeCategory(1,:,iCell), & - openWaterArea(iCell), & - tracerArrayCategory, & - snowVolumeCategoryInitial(:,iCell), & - config_use_skeletal_biochemistry, & - maxAlgaeType, & - nZBGCTracers, & - oceanBioFluxesCategory(:,:,iCell), & - bgridPorosityIceCell(:,iCell), & - bgridSalinityIceCell(:,iCell), & - bgridTemperatureIceCell(:,iCell), & - abortFlag, & - abortMessage) - call column_write_warnings(abortFlag) + ! code abort + abortFlag = .false. + abortMessage = "" + + call icepack_warnings_clear() + call icepack_biogeochemistry(& + dt=config_dt, & + ntrcr=ciceTracerObject % nTracers, & + nbtrcr=ciceTracerObject % nBioTracers, & + upNO=netNitrateUptake(iCell), & + upNH=netAmmoniumUptake(iCell), & + iDi=bioDiffusivity(:,:,iCell), & + iki=bioPermeability(:,:,iCell), & + zfswin=bioShortwaveFlux(:,:,iCell), & + zsal_tot=totalVerticalSalinity(iCell), & + darcy_V=darcyVelocityBio(:,iCell), & + grow_net=netSpecificAlgalGrowthRate(iCell), & + PP_net=primaryProduction(iCell), & + hbri=netBrineHeight(iCell), & + dhbr_bot=brineBottomChange(:,iCell), & + dhbr_top=brineTopChange(:,iCell), & + Zoo=verticalNitrogenLosses(:,:,iCell), & + fbio_snoice=snowIceBioFluxes(:,iCell), & + fbio_atmice=atmosIceBioFluxes(:,iCell), & + ocean_bio=oceanBioConcentrationsUsed(:), & + first_ice=newlyFormedIceLogical(:), & + fswpenln=shortwaveLayerPenetration(:,:,iCell), & + bphi=bioPorosity(:,:,iCell), & + bTiz=bioTemperature(:,:,iCell), & + ice_bio_net=totalVerticalBiologyIce(:,iCell), & + snow_bio_net=totalVerticalBiologySnow(:,iCell), & + totalChla=totalChlorophyll(iCell), & + fswthrun=penetratingShortwaveFlux(:,iCell), & + Rayleigh_criteria=rayleighCriteria, & + bgrid=biologyGrid, & + igrid=interfaceBiologyGrid, & + icgrid=interfaceGrid, & + cgrid=verticalGrid, & + nblyr=nBioLayers, & + nilyr=nIceLayers, & + nslyr=nSnowLayers, & + n_algae=nAlgae, & + n_zaero=nzAerosols, & + ncat=nCategories, & + n_doc=nDOC, & + n_dic=nDIC, & + n_don=nDON, & + n_fed=nDissolvedIron, & + n_fep=nParticulateIron, & + meltbn=basalIceMeltCategory(:,iCell), & + melttn=surfaceIceMeltCategory(:,iCell), & + congeln=congelationCategory(:,iCell), & + snoicen=snowiceFormationCategory(:,iCell), & + sst=seaSurfaceTemperature(iCell), & + sss=seaSurfaceSalinity(iCell), & + Tf=seaFreezingTemperature(iCell), & + fsnow=snowfallRate(iCell), & + meltsn=snowMeltCategory(:,iCell), & + !initialSalinityProfile(:,iCell), & !!!! + hin_old=iceThicknessCategoryInitial(:,iCell), & + flux_bio=oceanBioFluxes(:,iCell), & + flux_bio_atm=atmosBioFluxes(:,iCell), & + aicen_init=iceAreaCategoryInitial(:,iCell), & + vicen_init=iceVolumeCategoryInitial(:,iCell), & + aicen=iceAreaCategory(1,:,iCell), & + vicen=iceVolumeCategory(1,:,iCell), & + vsnon=snowVolumeCategory(1,:,iCell), & + aice0=openWaterArea(iCell), & + trcrn=tracerArrayCategory, & + vsnon_init=snowVolumeCategoryInitial(:,iCell), & + skl_bgc=config_use_skeletal_biochemistry, & + flux_bion=oceanBioFluxesCategory(:,:,iCell), & + bioPorosityIceCell=bgridPorosityIceCell(:,iCell), & + bioSalinityIceCell=bgridSalinityIceCell(:,iCell), & + bioTemperatureIceCell=bgridTemperatureIceCell(:,iCell)) + + abortFlag = icepack_warnings_aborted() + call seaice_icepack_write_warnings(abortFlag) call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) @@ -4076,9 +4059,6 @@ subroutine column_biogeochemistry(domain) enddo endif - ! code abort - if (abortFlag) exit - totalSkeletalAlgae(iCell) = 0.0_RKIND bioShortwaveFluxCell(:,iCell) = 0.0_RKIND @@ -4396,7 +4376,8 @@ subroutine seaice_icepack_aggregate(domain) ocean_coupling logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), dimension(:), pointer :: & iceAreaCell, & @@ -4431,6 +4412,7 @@ subroutine seaice_icepack_aggregate(domain) call MPAS_pool_get_subpool(block % structs, "ocean_coupling", ocean_coupling) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) call MPAS_pool_get_dimension(mesh, "nCategories", nCategories) @@ -4448,7 +4430,7 @@ subroutine seaice_icepack_aggregate(domain) call MPAS_pool_get_array(ocean_coupling, "seaFreezingTemperature", seaFreezingTemperature) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) do iCell = 1, nCellsSolve @@ -4597,7 +4579,8 @@ subroutine seaice_icepack_coupling_prep(domain) logical, pointer :: & config_use_ocean_mixed_layer, & config_include_pond_freshwater_feedback, & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols type(MPAS_pool_type), pointer :: & oceanCoupling, & @@ -4708,6 +4691,7 @@ subroutine seaice_icepack_coupling_prep(domain) call MPAS_pool_get_config(domain % configs, "config_dt", config_dt) call MPAS_pool_get_config(domain % configs, "config_include_pond_freshwater_feedback", config_include_pond_freshwater_feedback) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton) call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis) @@ -4900,10 +4884,12 @@ subroutine seaice_icepack_coupling_prep(domain) !----------------------------------------------------------------- ! Define ocean biogeochemical flux variables !----------------------------------------------------------------- - if (config_use_column_biogeochemistry) then + + oceanBioFluxesAll(:) = 0.0_RKIND + + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then totalOceanCarbonFlux(iCell) = 0.0_RKIND - oceanBioFluxesAll(:) = 0.0_RKIND oceanAlgaeFlux(:,iCell) = 0.0_RKIND oceanDOCFlux(:,iCell) = 0.0_RKIND oceanDICFlux(:,iCell) = 0.0_RKIND @@ -5014,7 +5000,7 @@ subroutine seaice_icepack_coupling_prep(domain) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanHumicsFlux(iCell) - endif ! config_use_column_biogeochemistry + endif ! config_use_column_biogeochemistry .or. config_use_zaerosols enddo ! iCell @@ -5062,7 +5048,8 @@ subroutine seaice_column_scale_fluxes(domain) mesh logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), dimension(:), pointer :: & iceAreaCell, & @@ -5122,6 +5109,7 @@ subroutine seaice_column_scale_fluxes(domain) iBioTracers call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) block => domain % blocklist do while (associated(block)) @@ -5214,6 +5202,9 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = albedoVisibleDiffuseCell(iCell) * iceAreaInverse albedoIRDiffuseCell(iCell) = albedoIRDiffuseCell(iCell) * iceAreaInverse + if (config_use_zaerosols) & + oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) * iceAreaInverse + if (config_use_column_biogeochemistry) then oceanNitrateFlux(iCell) = oceanNitrateFlux(iCell) * iceAreaInverse @@ -5223,7 +5214,6 @@ subroutine seaice_column_scale_fluxes(domain) oceanDMSPdFlux(iCell) = oceanDMSPdFlux(iCell) * iceAreaInverse oceanDMSFlux(iCell) = oceanDMSFlux(iCell) * iceAreaInverse oceanHumicsFlux(iCell) = oceanHumicsFlux(iCell) * iceAreaInverse - oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) * iceAreaInverse do iBioTracers = 1, maxAlgaeType oceanAlgaeFlux(iBioTracers,iCell) = oceanAlgaeFlux(iBioTracers,iCell) * iceAreaInverse @@ -5266,6 +5256,9 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = 0.0_RKIND albedoIRDiffuseCell(iCell) = 0.0_RKIND + if (config_use_zaerosols) & + oceanDustIronFlux(iCell) = 0.0_RKIND + if (config_use_column_biogeochemistry) then oceanNitrateFlux(iCell) = 0.0_RKIND @@ -5275,7 +5268,6 @@ subroutine seaice_column_scale_fluxes(domain) oceanDMSPdFlux(iCell) = 0.0_RKIND oceanDMSFlux(iCell) = 0.0_RKIND oceanHumicsFlux(iCell) = 0.0_RKIND - oceanDustIronFlux(iCell) = 0.0_RKIND oceanAlgaeFlux(:,iCell) = 0.0_RKIND oceanDOCFlux(:,iCell) = 0.0_RKIND oceanDICFlux(:,iCell) = 0.0_RKIND @@ -5994,12 +5986,14 @@ subroutine init_column_tracer_object(domain, tracerObject) nZBGCTracers logical, pointer :: & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nCategories", nCategories) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nZBGCTracers", nZBGCTracers) call MPAS_pool_get_config(domain % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) ! get the number of CICE tracers in trcrn call init_column_tracer_object_tracer_number(domain, tracerObject) @@ -6023,7 +6017,7 @@ subroutine init_column_tracer_object(domain, tracerObject) call init_column_tracer_object_ancestor_indices(domain, tracerObject) ! biogeochemistry - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then allocate(tracerObject % index_LayerIndexToDataArray(nZBGCTracers)) allocate(tracerObject % index_LayerIndexToBioIndex(nZBGCTracers)) @@ -6231,7 +6225,7 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject) ! biogeochemistry !----------------------------------------------------------------------- - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then ! save tracer number without bio tracers counted tracerObject % nTracersNotBio = tracerObject % nTracers @@ -6244,10 +6238,10 @@ subroutine init_column_tracer_object_tracer_number(domain, tracerObject) tracerObject % nTracers = tracerObject % nTracers + 1 ! vertical zSalinity - if (config_use_vertical_zsalinity) then - tracerObject % nTracers = tracerObject % nTracers + nBioLayers - tracerObject % nBioTracersLayer = tracerObject % nBioTracersLayer + 1 - endif + !if (config_use_vertical_zsalinity) then + ! tracerObject % nTracers = tracerObject % nTracers + nBioLayers + ! tracerObject % nBioTracersLayer = tracerObject % nBioTracersLayer + 1 + !endif nMobileTracers = 0 ! Skeletal Biogeochemistry @@ -9901,7 +9895,7 @@ subroutine check_column_package_configs(domain) config_use_vertical_biochemistry .or. config_use_shortwave_bioabsorption .or. config_use_vertical_tracers .or. & config_use_skeletal_biochemistry .or. config_use_nitrate .or. config_use_carbon .or. config_use_chlorophyll .or. & config_use_ammonium .or. config_use_silicate .or. config_use_DMS .or. config_use_nonreactive .or. config_use_humics .or. & - config_use_DON .or. config_use_iron .or. config_use_modal_aerosols .or. config_use_zaerosols)) then + config_use_DON .or. config_use_iron)) then call mpas_log_write(& "check_column_package_configs: config_use_column_biogeochemistry = false. "//& "All biogeochemistry namelist flags must also be false", & @@ -9909,12 +9903,12 @@ subroutine check_column_package_configs(domain) endif ! check vertical zSalinity requirements - if (config_use_vertical_zsalinity .and. ((.not. config_use_brine) .or. & - (.not. (trim(config_thermodynamics_type) == "BL99")))) then - call mpas_log_write(& - "check_column_package_configs: vertical zSalinity requires config_use_brine = true and 'BL99' ", & - messageType=MPAS_LOG_CRIT) - endif + !if (config_use_vertical_zsalinity .and. ((.not. config_use_brine) .or. & + ! (.not. (trim(config_thermodynamics_type) == "BL99")))) then + ! call mpas_log_write(& + ! "check_column_package_configs: vertical zSalinity requires config_use_brine = true and 'BL99' ", & + ! messageType=MPAS_LOG_CRIT) + !endif ! check that vertical bio tracers use brine height if ((config_use_vertical_biochemistry .or. config_use_zaerosols) .and. & @@ -10265,13 +10259,27 @@ subroutine init_icepack_package_tracer_sizes(domain, tracerObject) nIceLayers, & nSnowLayers, & nAerosols, & - nBioLayers + nBioLayers, & + nAlgae, & + nDOC, & + nDIC, & + nDON, & + nParticulateIron, & + nDissolvedIron, & + nzAerosols call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nCategories", nCategories) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nIceLayers", nIceLayers) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nSnowLayers", nSnowLayers) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nBioLayers", nBioLayers) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nAerosols", nAerosols) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nzAerosols", nzAerosols) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nAlgae", nAlgae) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDOC", nDOC) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDIC", nDIC) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDON", nDON) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nParticulateIron", nParticulateIron) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDissolvedIron", nDissolvedIron) call icepack_init_tracer_sizes(& ncat_in = nCategories, & @@ -10279,17 +10287,17 @@ subroutine init_icepack_package_tracer_sizes(domain, tracerObject) nslyr_in = nSnowLayers, & nblyr_in = nBioLayers, & !nfsd_in = , & - !n_algae_in = , & - !n_DOC_in = , & - n_aero_in = nAerosols, & !n_iso_in = , & - !n_DON_in = , & - !n_DIC_in = , & - !n_fed_in = , & - !n_fep_in = , & - !n_zaero_in = , & + !n_aero_in = nAerosols, & + n_algae_in = nAlgae, & + n_DOC_in = nDOC, & + n_DON_in = nDON, & + n_DIC_in = nDIC, & + n_fed_in = nDissolvedIron, & + n_fep_in = nParticulateIron, & + n_zaero_in = nzAerosols, & ntrcr_in = tracerObject % nTracers, & - !ntrcr_o_in = , & + ntrcr_o_in = tracerObject % nTracersNotBio, & nbtrcr_in = tracerObject % nBioTracers, & nbtrcr_sw_in = tracerObject % nBioTracersShortwave) @@ -10500,15 +10508,15 @@ subroutine init_column_package_tracer_indices(tracerObject) !nt_zbgc_S = tracerObject % index_verticalSalinity !nlt_chl_sw = tracerObject % index_chlorophyllShortwave !nlt_zaero_sw = tracerObject % index_verticalAerosolsConcShortwave - !max_algae = tracerObject % nAlgaeIndex - !max_algae = tracerObject % nAlgalCarbonIndex - !max_algae = tracerObject % nAlgalChlorophyllIndex - !max_doc = tracerObject % nDOCIndex - !max_don = tracerObject % nDONIndex - !max_dic = tracerObject % nDICIndex - !max_fe = tracerObject % nDissolvedIronIndex - !max_fe = tracerObject % nParticulateIronIndex - !max_aero = tracerObject % nzAerosolsIndex + !n_algae = tracerObject % nAlgaeIndex + !n_algae = tracerObject % nAlgalCarbonIndex + !n_algae = tracerObject % nAlgalChlorophyllIndex + !n_doc = tracerObject % nDOCIndex + !n_don = tracerObject % nDONIndex + !n_dic = tracerObject % nDICIndex + !n_fed = tracerObject % nDissolvedIronIndex + !n_fep = tracerObject % nParticulateIronIndex + !n_zaero = tracerObject % nzAerosolsIndex !bio_index_o = tracerObject % index_LayerIndexToDataArray !bio_index = tracerObject % index_LayerIndexToBioIndex !nbtrcr = tracerObject % nBioTracers @@ -12353,6 +12361,8 @@ subroutine init_icepack_package_configs(domain) config_use_skeletal_biochemistry, & config_use_vertical_zsalinity, & config_use_modal_aerosols, & + config_use_macromolecules, & + config_do_restart_bgc, & config_use_snow_liquid_ponds, & config_use_snow_grain_radius @@ -12607,6 +12617,8 @@ subroutine init_icepack_package_configs(domain) call MPAS_pool_get_config(domain % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols", config_use_modal_aerosols) + call MPAS_pool_get_config(domain % configs, "config_use_macromolecules", config_use_macromolecules) + call MPAS_pool_get_config(domain % configs, "config_do_restart_bgc", config_do_restart_bgc) call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) call MPAS_pool_get_config(domain % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) call MPAS_pool_get_config(domain % configs, "config_biogrid_bottom_molecular_sublayer", & @@ -13040,37 +13052,137 @@ subroutine init_icepack_package_configs(domain) z_tracers_in = config_use_vertical_tracers, & scale_bgc_in = config_scale_initial_vertical_bgc, & solve_zbgc_in = config_use_vertical_biochemistry, & + dEdd_algae_in = config_use_shortwave_bioabsorption, & modal_aero_in = config_use_modal_aerosols, & + use_macromolecules_in = config_use_macromolecules, & + restartbgc_in = config_do_restart_bgc, & skl_bgc_in = config_use_skeletal_biochemistry, & solve_zsal_in = config_use_vertical_zsalinity, & grid_o_in = config_biogrid_bottom_molecular_sublayer, & l_sk_in = config_bio_gravity_drainage_length_scale, & - initbio_frac_in = config_new_ice_fraction_biotracer, & + grid_o_t_in = config_biogrid_top_molecular_sublayer, & + !initbio_frac_in = config_new_ice_fraction_biotracer, & + !frazil_scav_in = config_fraction_biotracer_in_frazil, & grid_oS_in = config_zsalinity_molecular_sublayer, & l_skS_in = config_zsalinity_gravity_drainage_scale, & - dEdd_algae_in = config_use_shortwave_bioabsorption, & phi_snow_in = config_snow_porosity_at_ice_surface, & - !T_max_in = , & ! BGC - !fsal_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 = , & - !fr_dFe_in = , & - !k_nitrif_in = , & - !t_iron_conv_in = , & - !max_loss_in = , & - !max_dfe_doc1_in = , & - !fr_resp_s_in = , & + !ratio_Si2N_diatoms_in = config_ratio_Si_to_N_diatoms, & + !ratio_Si2N_sp_in = config_ratio_Si_to_N_small_plankton, & + !ratio_Si2N_phaeo_in = config_ratio_Si_to_N_phaeocystis, & + !ratio_S2N_diatoms_in = config_ratio_S_to_N_diatoms, & + !ratio_S2N_sp_in = config_ratio_S_to_N_small_plankton, & + !ratio_S2N_phaeo_in = config_ratio_S_to_N_phaeocystis, & + !ratio_Fe2C_diatoms_in = config_ratio_Fe_to_C_diatoms, & + !ratio_Fe2C_sp_in = config_ratio_Fe_to_C_small_plankton, & + !ratio_Fe2C_phaeo_in = config_ratio_Fe_to_C_phaeocystis, & + !ratio_Fe2N_diatoms_in = config_ratio_Fe_to_N_diatoms, & + !ratio_Fe2N_sp_in = config_ratio_Fe_to_N_small_plankton, & + !ratio_Fe2N_phaeo_in = config_ratio_Fe_to_N_phaeocystis, & + !ratio_Fe2DON_in = config_ratio_Fe_to_DON, & + !ratio_Fe2DOC_s_in = config_ratio_Fe_to_DOC_saccharids, & + !ratio_Fe2DOC_l_in = config_ratio_Fe_to_DOC_lipids, & + fr_resp_in = config_respiration_fraction_of_growth, & + tau_min_in = config_rapid_mobile_to_stationary_time, & + tau_max_in = config_long_mobile_to_stationary_time, & + algal_vel_in = config_algal_maximum_velocity, & + R_dFe2dust_in = config_ratio_Fe_to_dust, & + dustFe_sol_in = config_solubility_of_Fe_in_dust, & + !chlabs_diatoms_in = config_chla_absorptivity_of_diatoms, & + !chlabs_sp_in = config_chla_absorptivity_of_small_plankton, & + !chlabs_phaeo_in = config_chla_absorptivity_of_phaeocystis, & + !alpha2max_low_diatoms_in = config_light_attenuation_diatoms, & + !alpha2max_low_sp_in = config_light_attenuation_small_plankton, & + !alpha2max_low_phaeo_in = config_light_attenuation_phaeocystis, & + !beta2max_diatoms_in = config_light_inhibition_diatoms, & + !beta2max_sp_in = config_light_inhibition_small_plankton, & + !beta2max_phaeo_in = config_light_inhibition_phaeocystis, & + !mu_max_diatoms_in = config_maximum_growth_rate_diatoms, & + !mu_max_sp_in = config_maximum_growth_rate_small_plankton, & + !mu_max_phaeo_in = config_maximum_growth_rate_phaeocystis, & + !grow_Tdep_diatoms_in = config_temperature_growth_diatoms, & + !grow_Tdep_sp_in = config_temperature_growth_small_plankton, & + !grow_Tdep_phaeo_in = config_temperature_growth_phaeocystis, & + !fr_graze_diatoms_in = config_grazed_fraction_diatoms, & + !fr_graze_sp_in = config_grazed_fraction_small_plankton, & + !fr_graze_phaeo_in = config_grazed_fraction_phaeocystis, & + !mort_pre_diatoms_in = config_mortality_diatoms, & + !mort_pre_sp_in = config_mortality_small_plankton, & + !mort_pre_phaeo_in = config_mortality_phaeocystis, & + !mort_Tdep_diatoms_in = config_temperature_mortality_diatoms, & + !mort_Tdep_sp_in = config_temperature_mortality_small_plankton, & + !mort_Tdep_phaeo_in = config_temperature_mortality_phaeocystis, & + !k_exude_diatoms_in = config_exudation_diatoms, & + !k_exude_sp_in = config_exudation_small_plankton, & + !k_exude_phaeo_in = config_exudation_phaeocystis, & + !K_Nit_diatoms_in = config_nitrate_saturation_diatoms, & + !K_Nit_sp_in = config_nitrate_saturation_small_plankton, & + !K_Nit_phaeo_in = config_nitrate_saturation_phaeocystis, & + !K_Am_diatoms_in = config_ammonium_saturation_diatoms, & + !K_Am_sp_in = config_ammonium_saturation_small_plankton, & + !K_Am_phaeo_in = config_ammonium_saturation_phaeocystis, & + !K_Sil_diatoms_in = config_silicate_saturation_diatoms, & + !K_Sil_sp_in = config_silicate_saturation_small_plankton, & + !K_Sil_phaeo_in = config_silicate_saturation_phaeocystis, & + !K_Fe_diatoms_in = config_iron_saturation_diatoms, & + !K_Fe_sp_in = config_iron_saturation_small_plankton, & + !K_Fe_phaeo_in = config_iron_saturation_phaeocystis, & + !f_don_protein_in = config_fraction_spilled_to_DON, & + !kn_bac_protein_in = config_degredation_of_DON, & + !f_don_Am_protein_in = config_fraction_DON_ammonium, & + !f_doc_s_in = config_fraction_loss_to_saccharids, & + !f_doc_l_in = config_fraction_loss_to_lipids, & + !f_exude_s_in = config_fraction_exudation_to_saccharids, & + !f_exude_l_in = config_fraction_exudation_to_lipids, & + !k_bac_s_in = config_remineralization_saccharids, & + !k_bac_l_in = config_remineralization_lipids, & + T_max_in = config_maximum_brine_temperature, & + fsal_in = config_salinity_dependence_of_growth, & + op_dep_min_in = config_minimum_optical_depth, & + fr_graze_s_in = config_slopped_grazing_fraction, & + fr_graze_e_in = config_excreted_fraction, & + fr_mort2min_in = config_fraction_mortality_to_ammonium, & + fr_dFe_in = config_fraction_iron_remineralized, & + k_nitrif_in = config_nitrification_rate, & + t_iron_conv_in = config_desorption_loss_particulate_iron, & + max_loss_in = config_maximum_loss_fraction, & + max_dfe_doc1_in = config_maximum_ratio_iron_to_saccharids, & + fr_resp_s_in = config_respiration_loss_to_DMSPd, & + y_sk_DMS_in = config_DMSP_to_DMS_conversion_fraction, & + t_sk_conv_in = config_DMSP_to_DMS_conversion_time, & + t_sk_ox_in = config_DMS_oxidation_time, & + algaltype_diatoms_in = config_mobility_type_diatoms, & + algaltype_sp_in = config_mobility_type_small_plankton, & + algaltype_phaeo_in = config_mobility_type_phaeocystis, & + nitratetype_in = config_mobility_type_nitrate, & + ammoniumtype_in = config_mobility_type_ammonium, & + silicatetype_in = config_mobility_type_silicate, & + dmspptype_in = config_mobility_type_DMSPp, & + dmspdtype_in = config_mobility_type_DMSPd, & + humtype_in = config_mobility_type_humics, & + doctype_s_in = config_mobility_type_saccharids, & + doctype_l_in = config_mobility_type_lipids, & + dictype_1_in = config_mobility_type_inorganic_carbon, & + dontype_protein_in = config_mobility_type_proteins, & + fedtype_1_in = config_mobility_type_dissolved_iron, & + feptype_1_in = config_mobility_type_particulate_iron, & + zaerotype_bc1_in = config_mobility_type_black_carbon1, & + zaerotype_bc2_in = config_mobility_type_black_carbon2, & + zaerotype_dust1_in = config_mobility_type_dust1, & + zaerotype_dust2_in = config_mobility_type_dust2, & + zaerotype_dust3_in = config_mobility_type_dust3, & + zaerotype_dust4_in = config_mobility_type_dust4, & + ratio_C2N_diatoms_in = config_ratio_C_to_N_diatoms, & + ratio_C2N_sp_in = config_ratio_C_to_N_small_plankton, & + ratio_C2N_phaeo_in = config_ratio_C_to_N_phaeocystis, & + ratio_chl2N_diatoms_in = config_ratio_chla_to_N_diatoms, & + ratio_chl2N_sp_in = config_ratio_chla_to_N_small_plankton, & + ratio_chl2N_phaeo_in = config_ratio_chla_to_N_phaeocystis, & + F_abs_chl_diatoms_in = config_scales_absorption_diatoms, & + F_abs_chl_sp_in = config_scales_absorption_small_plankton, & + F_abs_chl_phaeo_in = config_scales_absorption_phaeocystis, & + ratio_C2N_proteins_in = config_ratio_C_to_N_proteins, & !conserv_check_in = , & - !y_sk_DMS_in = , & - !t_sk_conv_in = , & - !t_sk_ox_in = , & - !frazil_scav_in = , & + ! !sw_redist_in = , & ! not yet implemented in MPAS-SI (stealth feature) !sw_frac_in = , & ! not yet implemented in MPAS-SI (stealth feature) !sw_dtemp_in = , & ! not yet implemented in MPAS-SI (stealth feature) @@ -13153,124 +13265,6 @@ subroutine init_icepack_package_configs(domain) !call icepack_init_parameters(& ! shortwave = config_shortwave_type, & ! not working correctly above ! oceanmixed_ice = config_use_ocean_mixed_layer, & ! not used in Icepack/columnphysics (driver only) - ! grid_o_t = config_biogrid_top_molecular_sublayer, & ! not used in Icepack - ! frazil_scav = config_fraction_biotracer_in_frazil, & ! BGC - ! ratio_Si2N_diatoms = config_ratio_Si_to_N_diatoms, & - ! ratio_Si2N_sp = config_ratio_Si_to_N_small_plankton, & - ! ratio_Si2N_phaeo = config_ratio_Si_to_N_phaeocystis, & - ! ratio_S2N_diatoms = config_ratio_S_to_N_diatoms, & - ! ratio_S2N_sp = config_ratio_S_to_N_small_plankton, & - ! ratio_S2N_phaeo = config_ratio_S_to_N_phaeocystis, & - ! ratio_Fe2C_diatoms = config_ratio_Fe_to_C_diatoms, & - ! ratio_Fe2C_sp = config_ratio_Fe_to_C_small_plankton, & - ! ratio_Fe2C_phaeo = config_ratio_Fe_to_C_phaeocystis, & - ! ratio_Fe2N_diatoms = config_ratio_Fe_to_N_diatoms, & - ! ratio_Fe2N_sp = config_ratio_Fe_to_N_small_plankton, & - ! ratio_Fe2N_phaeo = config_ratio_Fe_to_N_phaeocystis, & - ! ratio_Fe2DON = config_ratio_Fe_to_DON, & - ! ratio_Fe2DOC_s = config_ratio_Fe_to_DOC_saccharids, & - ! ratio_Fe2DOC_l = config_ratio_Fe_to_DOC_lipids, & - ! fr_resp = config_respiration_fraction_of_growth, & - ! tau_min = config_rapid_mobile_to_stationary_time, & - ! tau_max = config_long_mobile_to_stationary_time, & - ! algal_vel = config_algal_maximum_velocity, & - ! R_dFe2dust = config_ratio_Fe_to_dust, & - ! dustFe_sol = config_solubility_of_Fe_in_dust, & - ! chlabs_diatoms = config_chla_absorptivity_of_diatoms, & - ! chlabs_sp = config_chla_absorptivity_of_small_plankton, & - ! chlabs_phaeo = config_chla_absorptivity_of_phaeocystis, & - ! alpha2max_low_diatoms = config_light_attenuation_diatoms, & - ! alpha2max_low_sp = config_light_attenuation_small_plankton, & - ! alpha2max_low_phaeo = config_light_attenuation_phaeocystis, & - ! beta2max_diatoms = config_light_inhibition_diatoms, & - ! beta2max_sp = config_light_inhibition_small_plankton, & - ! beta2max_phaeo = config_light_inhibition_phaeocystis, & - ! mu_max_diatoms = config_maximum_growth_rate_diatoms, & - ! mu_max_sp = config_maximum_growth_rate_small_plankton, & - ! mu_max_phaeo = config_maximum_growth_rate_phaeocystis, & - ! mu_max_diatoms = config_temperature_growth_diatoms, & ! rename - ! mu_max_sp = config_temperature_growth_small_plankton, & - ! mu_max_phaeo = config_temperature_growth_phaeocystis, & - ! fr_graze_diatoms = config_grazed_fraction_diatoms, & - ! fr_graze_sp = config_grazed_fraction_small_plankton, & - ! fr_graze_phaeo = config_grazed_fraction_phaeocystis, & - ! mort_pre_diatoms = config_mortality_diatoms, & - ! mort_pre_sp = config_mortality_small_plankton, & - ! mort_pre_phaeo = config_mortality_phaeocystis, & - ! mort_Tdep_diatoms = config_temperature_mortality_diatoms, & - ! mort_Tdep_sp = config_temperature_mortality_small_plankton, & - ! mort_Tdep_phaeo = config_temperature_mortality_phaeocystis, & - ! k_exude_diatoms = config_exudation_diatoms, & - ! k_exude_sp = config_exudation_small_plankton, & - ! k_exude_phaeo = config_exudation_phaeocystis, & - ! K_Nit_diatoms = config_nitrate_saturation_diatoms, & - ! K_Nit_sp = config_nitrate_saturation_small_plankton, & - ! K_Nit_phaeo = config_nitrate_saturation_phaeocystis, & - ! K_Am_diatoms = config_ammonium_saturation_diatoms, & - ! K_Am_sp = config_ammonium_saturation_small_plankton, & - ! K_Am_phaeo = config_ammonium_saturation_phaeocystis, & - ! K_Sil_diatoms = config_silicate_saturation_diatoms, & - ! K_Sil_sp = config_silicate_saturation_small_plankton, & - ! K_Sil_phaeo = config_silicate_saturation_phaeocystis, & - ! K_Fe_diatoms = config_iron_saturation_diatoms, & - ! K_Fe_sp = config_iron_saturation_small_plankton, & - ! K_Fe_phaeo = config_iron_saturation_phaeocystis, & - ! f_don_protein = config_fraction_spilled_to_DON, & - ! kn_bac_protein = config_degredation_of_DON, & - ! f_don_Am_protein = config_fraction_DON_ammonium, & - ! f_doc_s = config_fraction_loss_to_saccharids, & - ! f_doc_l = config_fraction_loss_to_lipids, & - ! f_exude_s = config_fraction_exudation_to_saccharids, & - ! f_exude_l = config_fraction_exudation_to_lipids, & - ! k_bac_s = config_remineralization_saccharids, & - ! k_bac_l = config_remineralization_lipids, & - ! T_max = config_maximum_brine_temperature, & - ! fsal = config_salinity_dependence_of_growth, & - ! op_dep_min = config_minimum_optical_depth, & - ! fr_graze_s = config_slopped_grazing_fraction, & - ! fr_graze_e = config_excreted_fraction, & - ! fr_mort2min = config_fraction_mortality_to_ammonium, & - ! fr_dFe = config_fraction_iron_remineralized, & - ! k_nitrif = config_nitrification_rate, & - ! t_iron_conv = config_desorption_loss_particulate_iron, & - ! max_loss = config_maximum_loss_fraction, & - ! max_dfe_doc1 = config_maximum_ratio_iron_to_saccharids, & - ! fr_resp_s = config_respiration_loss_to_DMSPd, & - ! y_sk_DMS = config_DMSP_to_DMS_conversion_fraction, & - ! t_sk_conv = config_DMSP_to_DMS_conversion_time, & - ! t_sk_ox = config_DMS_oxidation_time, & - ! algaltype_diatoms = config_mobility_type_diatoms, & - ! algaltype_sp = config_mobility_type_small_plankton, & - ! algaltype_phaeo = config_mobility_type_phaeocystis, & - ! nitratetype = config_mobility_type_nitrate, & - ! ammoniumtype = config_mobility_type_ammonium, & - ! silicatetype = config_mobility_type_silicate, & - ! dmspptype = config_mobility_type_DMSPp, & - ! dmspdtype = config_mobility_type_DMSPd, & - ! humicstype = config_mobility_type_humics, & - ! doctype_s = config_mobility_type_saccharids, & - ! dictype_1 = config_mobility_type_lipids, & - ! dictype_1 = config_mobility_type_inorganic_carbon, & - ! dontype_protein = config_mobility_type_proteins, & - ! fedtype_1 = config_mobility_type_dissolved_iron, & - ! feptype_1 = config_mobility_type_particulate_iron, & - ! zaerotype_bc1 = config_mobility_type_black_carbon1, & - ! zaerotype_bc2 = config_mobility_type_black_carbon2, & - ! zaerotype_dust1 = config_mobility_type_dust1, & - ! zaerotype_dust2 = config_mobility_type_dust2, & - ! zaerotype_dust3 = config_mobility_type_dust3, & - ! zaerotype_dust4 = config_mobility_type_dust4, & - ! ratio_C2N_diatoms = config_ratio_C_to_N_diatoms, & - ! ratio_C2N_sp = config_ratio_C_to_N_small_plankton, & - ! ratio_C2N_phaeo = config_ratio_C_to_N_phaeocystis, & - ! ratio_chl2N_diatoms = config_ratio_chla_to_N_diatoms, & - ! ratio_chl2N_sp = config_ratio_chla_to_N_small_plankton, & - ! ratio_chl2N_phaeo = config_ratio_chla_to_N_phaeocystis, & - ! F_abs_chl_diatoms = config_scales_absorption_diatoms, & - ! F_abs_chl_sp = config_scales_absorption_small_plankton, & - ! F_abs_chl_phaeo = config_scales_absorption_phaeocystis, & - ! ratio_C2N_proteins = config_ratio_C_to_N_proteins, & - !----------------------------------------------------------------------- ! Parameters for thermodynamics !----------------------------------------------------------------------- @@ -15210,7 +15204,8 @@ end subroutine seaice_column_reinitialize_oceanic_fluxes subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) - use ice_colpkg, only: colpkg_init_zbgc + !use ice_colpkg, only: colpkg_init_zbgc + use icepack_intfc, only: icepack_init_zbgc type(domain_type), intent(in) :: & domain @@ -15550,188 +15545,186 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) allocate(tracerObject % index_dissolvedIronConcLayer(maxIronType)) tracerObject % nDissolvedIronIndex = nDissolvedIron - call colpkg_init_zbgc(& - nBioLayers, & - nIceLayers, & - nSnowLayers, & - nAlgae, & - nzAerosols, & - nDOC, & - nDIC, & - nDON, & - nDissolvedIron, & - nParticulateIron, & - tracerObject % firstAncestorMask, & - tracerObject % parentIndex, & - tracerObject % ancestorNumber, & - tracerObject % ancestorIndices, & - tracerObject % nBioTracersShortwave, & - config_use_brine, & - tracerObject % index_brineFraction,& - tracerObject % nTracers, & - tracerObject % nBioTracers, & - tracerObject % index_nitrateConc, & - tracerObject % index_ammoniumConc, & - tracerObject % index_silicateConc, & - tracerObject % index_DMSConc, & - tracerObject % index_nonreactiveConc, & - tracerObject % index_verticalSalinity, & - tracerObject % index_algaeConc, & - tracerObject % index_algalCarbon, & - tracerObject % index_algalChlorophyll, & - tracerObject % index_DOCConc, & - tracerObject % index_DONConc, & - tracerObject % index_DICConc, & - tracerObject % index_verticalAerosolsConc, & - tracerObject % index_DMSPpConc, & - tracerObject % index_DMSPdConc, & - tracerObject % index_dissolvedIronConc, & - tracerObject % index_particulateIronConc, & - tracerObject % index_mobileFraction, & - config_use_nitrate, & - config_use_ammonium, & - config_use_silicate, & - config_use_DMS, & - config_use_nonreactive, & - config_use_vertical_zsalinity, & - use_nitrogen, & - config_use_carbon, & - config_use_chlorophyll, & - config_use_DON, & - config_use_iron,& - config_use_zaerosols, & - tracerObject % index_verticalAerosolsConcShortwave, & - tracerObject % index_chlorophyllShortwave, & - tracerObject % index_algaeConcLayer, & - tracerObject % index_nitrateConcLayer, & - tracerObject % index_ammoniumConcLayer, & - tracerObject % index_silicateConcLayer, & - tracerObject % index_DMSConcLayer, & - tracerObject % index_DMSPpConcLayer, & - tracerObject % index_DMSPdConcLayer, & - tracerObject % index_algalCarbonLayer, & - tracerObject % index_algalChlorophyllLayer, & - tracerObject % index_DICConcLayer, & - tracerObject % index_DOCConcLayer, & - tracerObject % index_nonreactiveConcLayer, & - tracerObject % index_DONConcLayer, & - tracerObject % index_dissolvedIronConcLayer, & - tracerObject % index_particulateIronConcLayer, & - tracerObject % index_verticalAerosolsConcLayer, & - tracerObject % index_humicsConc, & - tracerObject % index_humicsConcLayer, & - config_use_humics, & - config_use_vertical_zsalinity, & - config_use_skeletal_biochemistry, & - config_use_vertical_tracers, & - config_use_shortwave_bioabsorption, & - config_use_vertical_biochemistry, & - config_fraction_biotracer_in_frazil, & - config_new_ice_fraction_biotracer, & - tracerObject % index_LayerIndexToDataArray, & - tracerObject % index_LayerIndexToBioIndex, & - tracerObject % nTracersNotBio, & - maxAlgaeType, & - maxDOCType, & - maxDICType, & - maxDONType, & - maxIronType, & - config_ratio_Si_to_N_diatoms, & - config_ratio_Si_to_N_small_plankton, & - config_ratio_Si_to_N_phaeocystis, & - config_ratio_S_to_N_diatoms, & - config_ratio_S_to_N_small_plankton, & - config_ratio_S_to_N_phaeocystis, & - config_ratio_Fe_to_C_diatoms, & - config_ratio_Fe_to_C_small_plankton, & - config_ratio_Fe_to_C_phaeocystis, & - config_ratio_Fe_to_N_diatoms, & - config_ratio_Fe_to_N_small_plankton, & - config_ratio_Fe_to_N_phaeocystis, & - config_ratio_Fe_to_DON, & - config_ratio_Fe_to_DOC_saccharids, & - config_ratio_Fe_to_DOC_lipids, & - config_chla_absorptivity_of_diatoms, & - config_chla_absorptivity_of_small_plankton, & - config_chla_absorptivity_of_phaeocystis, & - config_light_attenuation_diatoms, & - config_light_attenuation_small_plankton, & - config_light_attenuation_phaeocystis, & - config_light_inhibition_diatoms, & - config_light_inhibition_small_plankton, & - config_light_inhibition_phaeocystis, & - config_maximum_growth_rate_diatoms, & - config_maximum_growth_rate_small_plankton, & - config_maximum_growth_rate_phaeocystis, & - config_temperature_growth_diatoms, & - config_temperature_growth_small_plankton, & - config_temperature_growth_phaeocystis, & - config_grazed_fraction_diatoms, & - config_grazed_fraction_small_plankton, & - config_grazed_fraction_phaeocystis, & - config_mortality_diatoms, & - config_mortality_small_plankton, & - config_mortality_phaeocystis, & - config_temperature_mortality_diatoms, & - config_temperature_mortality_small_plankton, & - config_temperature_mortality_phaeocystis, & - config_exudation_diatoms, & - config_exudation_small_plankton, & - config_exudation_phaeocystis, & - config_nitrate_saturation_diatoms, & - config_nitrate_saturation_small_plankton, & - config_nitrate_saturation_phaeocystis, & - config_ammonium_saturation_diatoms, & - config_ammonium_saturation_small_plankton, & - config_ammonium_saturation_phaeocystis, & - config_silicate_saturation_diatoms, & - config_silicate_saturation_small_plankton, & - config_silicate_saturation_phaeocystis, & - config_iron_saturation_diatoms, & - config_iron_saturation_small_plankton, & - config_iron_saturation_phaeocystis, & - config_fraction_spilled_to_DON, & - config_degredation_of_DON, & - config_fraction_DON_ammonium, & - config_fraction_loss_to_saccharids, & - config_fraction_loss_to_lipids, & - config_fraction_exudation_to_saccharids, & - config_fraction_exudation_to_lipids, & - config_remineralization_saccharids, & - config_remineralization_lipids, & - config_mobility_type_diatoms, & - config_mobility_type_small_plankton, & - config_mobility_type_phaeocystis, & - config_mobility_type_saccharids, & - config_mobility_type_lipids, & - config_mobility_type_inorganic_carbon, & - config_mobility_type_proteins, & - config_mobility_type_dissolved_iron, & - config_mobility_type_particulate_iron, & - config_mobility_type_black_carbon1, & - config_mobility_type_black_carbon2, & - config_mobility_type_dust1, & - config_mobility_type_dust2, & - config_mobility_type_dust3, & - config_mobility_type_dust4, & - config_ratio_C_to_N_diatoms, & - config_ratio_C_to_N_small_plankton, & - config_ratio_C_to_N_phaeocystis, & - config_ratio_chla_to_N_diatoms, & - config_ratio_chla_to_N_small_plankton, & - config_ratio_chla_to_N_phaeocystis, & - config_scales_absorption_diatoms, & - config_scales_absorption_small_plankton, & - config_scales_absorption_phaeocystis, & - config_ratio_C_to_N_proteins, & - config_mobility_type_nitrate, & - config_mobility_type_ammonium, & - config_mobility_type_DMSPp, & - config_mobility_type_DMSPd, & - config_mobility_type_silicate, & - config_mobility_type_humics, & - config_rapid_mobile_to_stationary_time, & - config_long_mobile_to_stationary_time) + call icepack_init_zbgc(& + nblyr=nBioLayers, & + nilyr=nIceLayers, & + nslyr=nSnowLayers, & + n_algae=nAlgae, & + n_zaero=nzAerosols, & + n_doc=nDOC, & + n_dic=nDIC, & + n_don=nDON, & + n_fed=nDissolvedIron, & + n_fep=nParticulateIron, & + trcr_base=tracerObject % firstAncestorMask, & + trcr_depend=tracerObject % parentIndex, & + n_trcr_strata=tracerObject % ancestorNumber, & + nt_strata=tracerObject % ancestorIndices, & + nbtrcr_sw=tracerObject % nBioTracersShortwave, & + tr_brine=config_use_brine, & + nt_fbri=tracerObject % index_brineFraction,& + ntrcr=tracerObject % nTracers, & + nbtrcr=tracerObject % nBioTracers, & + nt_bgc_Nit=tracerObject % index_nitrateConc, & + nt_bgc_Am=tracerObject % index_ammoniumConc, & + nt_bgc_Sil=tracerObject % index_silicateConc, & + nt_bgc_DMS=tracerObject % index_DMSConc, & + nt_bgc_PON=tracerObject % index_nonreactiveConc, & + nt_bgc_S=tracerObject % index_verticalSalinity, & + nt_bgc_N=tracerObject % index_algaeConc, & + nt_bgc_C=tracerObject % index_algalCarbon, & + nt_bgc_chl=tracerObject % index_algalChlorophyll, & + nt_bgc_DOC=tracerObject % index_DOCConc, & + nt_bgc_DON=tracerObject % index_DONConc, & + nt_bgc_DIC=tracerObject % index_DICConc, & + nt_zaero=tracerObject % index_verticalAerosolsConc, & + nt_bgc_DMSPp=tracerObject % index_DMSPpConc, & + nt_bgc_DMSPd=tracerObject % index_DMSPdConc, & + nt_bgc_Fed=tracerObject % index_dissolvedIronConc, & + nt_bgc_Fep=tracerObject % index_particulateIronConc, & + nt_zbgc_frac=tracerObject % index_mobileFraction, & + tr_bgc_Nit=config_use_nitrate, & + tr_bgc_Am=config_use_ammonium, & + tr_bgc_Sil=config_use_silicate, & + tr_bgc_DMS=config_use_DMS, & + tr_bgc_PON=config_use_nonreactive, & + tr_bgc_N=use_nitrogen, & + tr_bgc_C=config_use_carbon, & + tr_bgc_chl=config_use_chlorophyll, & + tr_bgc_DON=config_use_DON, & + tr_bgc_Fe=config_use_iron,& + tr_zaero=config_use_zaerosols, & + nlt_zaero_sw=tracerObject % index_verticalAerosolsConcShortwave, & + nlt_chl_sw=tracerObject % index_chlorophyllShortwave, & + nlt_bgc_N=tracerObject % index_algaeConcLayer, & + nlt_bgc_Nit=tracerObject % index_nitrateConcLayer, & + nlt_bgc_Am=tracerObject % index_ammoniumConcLayer, & + nlt_bgc_Sil=tracerObject % index_silicateConcLayer, & + nlt_bgc_DMS=tracerObject % index_DMSConcLayer, & + nlt_bgc_DMSPp=tracerObject % index_DMSPpConcLayer, & + nlt_bgc_DMSPd=tracerObject % index_DMSPdConcLayer, & + nlt_bgc_C=tracerObject % index_algalCarbonLayer, & + nlt_bgc_chl=tracerObject % index_algalChlorophyllLayer, & + nlt_bgc_DIC=tracerObject % index_DICConcLayer, & + nlt_bgc_DOC=tracerObject % index_DOCConcLayer, & + nlt_bgc_PON=tracerObject % index_nonreactiveConcLayer, & + nlt_bgc_DON=tracerObject % index_DONConcLayer, & + nlt_bgc_Fed=tracerObject % index_dissolvedIronConcLayer, & + nlt_bgc_Fep=tracerObject % index_particulateIronConcLayer, & + nlt_zaero=tracerObject % index_verticalAerosolsConcLayer, & + nt_bgc_hum=tracerObject % index_humicsConc, & + nlt_bgc_hum=tracerObject % index_humicsConcLayer, & + tr_bgc_hum=config_use_humics, & + skl_bgc=config_use_skeletal_biochemistry, & + z_tracers=config_use_vertical_tracers, & + dEdd_algae=config_use_shortwave_bioabsorption, & + solve_zbgc=config_use_vertical_biochemistry, & + frazil_scav_in=config_fraction_biotracer_in_frazil, & + initbio_frac_in=config_new_ice_fraction_biotracer, & + bio_index_o_out=tracerObject % index_LayerIndexToDataArray, & + bio_index_out=tracerObject % index_LayerIndexToBioIndex, & + ntrcr_o=tracerObject % nTracersNotBio, & + max_algae_in=maxAlgaeType, & + max_doc_in=maxDOCType, & + max_dic_in=maxDICType, & + max_don_in=maxDONType, & + max_fe_in=maxIronType, & + ratio_Si2N_diatoms_in=config_ratio_Si_to_N_diatoms, & + ratio_Si2N_sp_in=config_ratio_Si_to_N_small_plankton, & + ratio_Si2N_phaeo_in=config_ratio_Si_to_N_phaeocystis, & + ratio_S2N_diatoms_in=config_ratio_S_to_N_diatoms, & + ratio_S2N_sp_in=config_ratio_S_to_N_small_plankton, & + ratio_S2N_phaeo_in=config_ratio_S_to_N_phaeocystis, & + ratio_Fe2C_diatoms_in=config_ratio_Fe_to_C_diatoms, & + ratio_Fe2C_sp_in=config_ratio_Fe_to_C_small_plankton, & + ratio_Fe2C_phaeo_in=config_ratio_Fe_to_C_phaeocystis, & + ratio_Fe2N_diatoms_in=config_ratio_Fe_to_N_diatoms, & + ratio_Fe2N_sp_in=config_ratio_Fe_to_N_small_plankton, & + ratio_Fe2N_phaeo_in=config_ratio_Fe_to_N_phaeocystis, & + ratio_Fe2DON_in=config_ratio_Fe_to_DON, & + ratio_Fe2DOC_s_in=config_ratio_Fe_to_DOC_saccharids, & + ratio_Fe2DOC_l_in=config_ratio_Fe_to_DOC_lipids, & + chlabs_diatoms_in=config_chla_absorptivity_of_diatoms, & + chlabs_sp_in=config_chla_absorptivity_of_small_plankton, & + chlabs_phaeo_in=config_chla_absorptivity_of_phaeocystis, & + alpha2max_low_diatoms_in=config_light_attenuation_diatoms, & + alpha2max_low_sp_in=config_light_attenuation_small_plankton, & + alpha2max_low_phaeo_in=config_light_attenuation_phaeocystis, & + beta2max_diatoms_in=config_light_inhibition_diatoms, & + beta2max_sp_in=config_light_inhibition_small_plankton, & + beta2max_phaeo_in=config_light_inhibition_phaeocystis, & + mu_max_diatoms_in=config_maximum_growth_rate_diatoms, & + mu_max_sp_in=config_maximum_growth_rate_small_plankton, & + mu_max_phaeo_in=config_maximum_growth_rate_phaeocystis, & + grow_Tdep_diatoms_in=config_temperature_growth_diatoms, & + grow_Tdep_sp_in=config_temperature_growth_small_plankton, & + grow_Tdep_phaeo_in=config_temperature_growth_phaeocystis, & + fr_graze_diatoms_in=config_grazed_fraction_diatoms, & + fr_graze_sp_in=config_grazed_fraction_small_plankton, & + fr_graze_phaeo_in=config_grazed_fraction_phaeocystis, & + mort_pre_diatoms_in=config_mortality_diatoms, & + mort_pre_sp_in=config_mortality_small_plankton, & + mort_pre_phaeo_in=config_mortality_phaeocystis, & + mort_Tdep_diatoms_in=config_temperature_mortality_diatoms, & + mort_Tdep_sp_in=config_temperature_mortality_small_plankton, & + mort_Tdep_phaeo_in=config_temperature_mortality_phaeocystis, & + k_exude_diatoms_in=config_exudation_diatoms, & + k_exude_sp_in=config_exudation_small_plankton, & + k_exude_phaeo_in=config_exudation_phaeocystis, & + K_Nit_diatoms_in=config_nitrate_saturation_diatoms, & + K_Nit_sp_in=config_nitrate_saturation_small_plankton, & + K_Nit_phaeo_in=config_nitrate_saturation_phaeocystis, & + K_Am_diatoms_in=config_ammonium_saturation_diatoms, & + K_Am_sp_in=config_ammonium_saturation_small_plankton, & + K_Am_phaeo_in=config_ammonium_saturation_phaeocystis, & + K_Sil_diatoms_in=config_silicate_saturation_diatoms, & + K_Sil_sp_in=config_silicate_saturation_small_plankton, & + K_Sil_phaeo_in=config_silicate_saturation_phaeocystis, & + K_Fe_diatoms_in=config_iron_saturation_diatoms, & + K_Fe_sp_in=config_iron_saturation_small_plankton, & + K_Fe_phaeo_in=config_iron_saturation_phaeocystis, & + f_don_protein_in=config_fraction_spilled_to_DON, & + kn_bac_protein_in=config_degredation_of_DON, & + f_don_Am_protein_in=config_fraction_DON_ammonium, & + f_doc_s_in=config_fraction_loss_to_saccharids, & + f_doc_l_in=config_fraction_loss_to_lipids, & + f_exude_s_in=config_fraction_exudation_to_saccharids, & + f_exude_l_in=config_fraction_exudation_to_lipids, & + k_bac_s_in=config_remineralization_saccharids, & + k_bac_l_in=config_remineralization_lipids, & + algaltype_diatoms_in=config_mobility_type_diatoms, & + algaltype_sp_in=config_mobility_type_small_plankton, & + algaltype_phaeo_in=config_mobility_type_phaeocystis, & + doctype_s_in=config_mobility_type_saccharids, & + doctype_l_in=config_mobility_type_lipids, & + dictype_1_in=config_mobility_type_inorganic_carbon, & + dontype_protein_in=config_mobility_type_proteins, & + fedtype_1_in=config_mobility_type_dissolved_iron, & + feptype_1_in=config_mobility_type_particulate_iron, & + zaerotype_bc1_in=config_mobility_type_black_carbon1, & + zaerotype_bc2_in=config_mobility_type_black_carbon2, & + zaerotype_dust1_in=config_mobility_type_dust1, & + zaerotype_dust2_in=config_mobility_type_dust2, & + zaerotype_dust3_in=config_mobility_type_dust3, & + zaerotype_dust4_in=config_mobility_type_dust4, & + ratio_C2N_diatoms_in=config_ratio_C_to_N_diatoms, & + ratio_C2N_sp_in=config_ratio_C_to_N_small_plankton, & + ratio_C2N_phaeo_in=config_ratio_C_to_N_phaeocystis, & + ratio_chl2N_diatoms_in=config_ratio_chla_to_N_diatoms, & + ratio_chl2N_sp_in=config_ratio_chla_to_N_small_plankton, & + ratio_chl2N_phaeo_in=config_ratio_chla_to_N_phaeocystis, & + F_abs_chl_diatoms_in=config_scales_absorption_diatoms, & + F_abs_chl_sp_in=config_scales_absorption_small_plankton, & + F_abs_chl_phaeo_in=config_scales_absorption_phaeocystis, & + ratio_C2N_proteins_in=config_ratio_C_to_N_proteins, & + nitratetype_in=config_mobility_type_nitrate, & + ammoniumtype_in=config_mobility_type_ammonium, & + dmspptype_in=config_mobility_type_DMSPp, & + dmspdtype_in=config_mobility_type_DMSPd, & + silicatetype_in=config_mobility_type_silicate, & + humtype_in=config_mobility_type_humics, & + tau_min_in=config_rapid_mobile_to_stationary_time, & + tau_max_in=config_long_mobile_to_stationary_time) ! check calculated tracer array size if (nTracers_temp /= tracerObject % nTracers) then @@ -15756,10 +15749,15 @@ end subroutine init_column_tracer_object_for_biogeochemistry subroutine init_column_biogeochemistry_profiles(domain, tracerObject) - use ice_colpkg, only: & - colpkg_init_bgc, & - colpkg_init_hbrine, & - colpkg_init_zsalinity + !use ice_colpkg, only: & + ! colpkg_init_bgc, & + ! colpkg_init_hbrine, & + ! colpkg_init_zsalinity + + use icepack_intfc, only: & + icepack_init_bgc, & + icepack_init_hbrine, & + icepack_load_ocean_bio_array type(domain_type), intent(inout) :: domain @@ -15781,9 +15779,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) config_use_vertical_tracers, & config_use_skeletal_biochemistry, & config_do_restart_zsalinity, & - config_do_restart_bgc, & - config_do_restart_hbrine, & - config_use_macromolecules + config_do_restart_hbrine real(kind=RKIND), pointer :: & config_dt, & @@ -15837,14 +15833,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) nBioLayersP1, & nBioLayersP2, & nCategories, & - nShortwaveBio, & - nZBGCTracers, & - maxAerosolType, & - maxAlgaeType, & - maxDOCType, & - maxDICType, & - maxDONType, & - maxIronType + nShortwaveBio integer :: & iCell @@ -15860,14 +15849,12 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) call MPAS_pool_get_config(domain % configs, "config_use_brine", config_use_brine) call MPAS_pool_get_config(domain % configs, "config_do_restart_zsalinity", config_do_restart_zsalinity) - call MPAS_pool_get_config(domain % configs, "config_do_restart_bgc", config_do_restart_bgc) call MPAS_pool_get_config(domain % configs, "config_do_restart_hbrine", config_do_restart_hbrine) call MPAS_pool_get_config(domain % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) call MPAS_pool_get_config(domain % configs, "config_use_vertical_tracers", config_use_vertical_tracers) call MPAS_pool_get_config(domain % configs, "config_dt", config_dt) call MPAS_pool_get_config(domain % configs, "config_snow_porosity_at_ice_surface", config_snow_porosity_at_ice_surface) - call MPAS_pool_get_config(domain % configs, "config_use_macromolecules", config_use_macromolecules) abortFlag = .false. @@ -15926,23 +15913,15 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1) call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP2", nBioLayersP2) call MPAS_pool_get_dimension(block % dimensions, "nShortwaveBio", nShortwaveBio) - call MPAS_pool_get_dimension(block % dimensions, "nZBGCTracers", nZBGCTracers) - call MPAS_pool_get_dimension(block % dimensions, "maxAerosolType", maxAerosolType) - call MPAS_pool_get_dimension(block % dimensions, "maxAlgaeType", maxAlgaeType) - call MPAS_pool_get_dimension(block % dimensions, "maxDOCType", maxDOCType) - call MPAS_pool_get_dimension(block % dimensions, "maxDICType", maxDICType) - call MPAS_pool_get_dimension(block % dimensions, "maxDONType", maxDONType) - call MPAS_pool_get_dimension(block % dimensions, "maxIronType", maxIronType) - - call colpkg_init_hbrine(& - biologyGrid, & - interfaceBiologyGrid, & - verticalGrid, & - interfaceGrid, & - verticalShortwaveGrid, & - nBioLayers, & - nIceLayers, & - config_snow_porosity_at_ice_surface) + call icepack_init_hbrine(& + bgrid=biologyGrid, & + igrid=interfaceBiologyGrid, & + cgrid=verticalGrid, & + icgrid=interfaceGrid, & + swgrid=verticalShortwaveGrid, & + nblyr=nBioLayers, & + nilyr=nIceLayers, & + phi_snow=config_snow_porosity_at_ice_surface) do iCell = 1, nCellsSolve if (.not. config_do_restart_hbrine) then @@ -15957,65 +15936,41 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) call set_cice_tracer_array_category(block, tracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (config_use_vertical_zsalinity) then - call colpkg_init_zsalinity(& - nBioLayers, & - tracerObject % nTracersNotBio, & - config_do_restart_zsalinity, & - rayleighCriteria, & - rayleighCriteriaReal(iCell), & - tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), & - tracerObject % index_verticalSalinity, & - nCategories, & - seaSurfaceSalinity(iCell)) - endif - if (config_use_vertical_tracers .or. config_use_skeletal_biochemistry) then - call colpkg_init_bgc(& - config_dt, & - nCategories, & - nBioLayers, & - nIceLayers, & - tracerObject % nTracersNotBio, & - verticalGrid, & - interfaceBiologyGrid, & - config_do_restart_bgc, & - tracerObject % nTracers, & - tracerObject % nBiotracers, & - iceSalinity(:,:,iCell), & - tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), & - seaSurfaceSalinity(iCell), & - oceanNitrateConc(iCell), & - oceanAmmoniumConc(iCell), & - oceanSilicateConc(iCell), & - oceanDMSPConc(iCell), & - oceanDMSConc(iCell), & - oceanAlgaeConc(:,iCell), & - oceanDOCConc(:,iCell), & - oceanDONConc(:,iCell), & - oceanDICConc(:,iCell), & - oceanDissolvedIronConc(:,iCell), & - oceanParticulateIronConc(:,iCell), & - oceanZAerosolConc(:,iCell), & - oceanHumicsConc(iCell), & - oceanBioConcentrations(:,iCell), & - maxAlgaeType, & - maxDOCType, & - maxDICType, & - maxDONType, & - maxIronType, & - nZBGCTracers, & - maxAerosolType, & - DOCPoolFractions, & - config_use_macromolecules, & - abortFlag, & - abortMessage) - - if (abortFlag) then - call mpas_log_write(& - "init_column_biogeochemistry_profiles: colpkg_init_bgc: "//trim(abortMessage), & - messageType=MPAS_LOG_CRIT) - endif + + call icepack_load_ocean_bio_array(& + nit=oceanNitrateConc(iCell), & + amm=oceanAmmoniumConc(iCell), & + sil=oceanSilicateConc(iCell), & + dmsp=oceanDMSPConc(iCell), & + dms=oceanDMSConc(iCell), & + algalN=oceanAlgaeConc(:,iCell), & + doc=oceanDOCConc(:,iCell), & + don=oceanDONConc(:,iCell), & + dic=oceanDICConc(:,iCell), & + fed=oceanDissolvedIronConc(:,iCell), & + fep=oceanParticulateIronConc(:,iCell), & + zaeros=oceanZAerosolConc(:,iCell), & + ocean_bio_all=oceanBioConcentrations(:,iCell), & + hum=oceanHumicsConc(iCell)) + + call icepack_init_bgc(& + ncat=nCategories, & + nblyr=nBioLayers, & + nilyr=nIceLayers, & + ntrcr_o=tracerObject % nTracersNotBio, & + cgrid=verticalGrid, & + igrid=interfaceBiologyGrid, & + ntrcr=tracerObject % nTracers, & + nbtrcr=tracerObject % nBiotracers, & + sicen=iceSalinity(:,:,iCell), & + trcrn=tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), & + sss=seaSurfaceSalinity(iCell), & + ocean_bio_all=oceanBioConcentrations(:,iCell), & + DOCPoolFractions=DOCPoolFractions) + + call seaice_icepack_write_warnings(icepack_warnings_aborted()) + endif ! biogeochemistry ! get the category tracer array @@ -16527,8 +16482,9 @@ subroutine seaice_icepack_reinitialize_diagnostics_bgc(domain) config_use_column_biogeochemistry, & config_use_column_shortwave, & config_use_column_package, & - config_use_vertical_biochemistry, & - config_use_vertical_zsalinity + config_use_vertical_tracers, & + config_use_vertical_zsalinity, & + config_use_zaerosols call MPAS_pool_get_config(domain % blocklist % configs, "config_use_column_package", config_use_column_package) @@ -16539,15 +16495,16 @@ subroutine seaice_icepack_reinitialize_diagnostics_bgc(domain) ! biogeochemistry call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) - call MPAS_pool_get_config(block % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) + call MPAS_pool_get_config(block % configs, "config_use_vertical_tracers", config_use_vertical_tracers) call MPAS_pool_get_config(block % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistryPool) call MPAS_pool_get_subpool(block % structs, "diagnostics_biogeochemistry", diagnostics_biogeochemistryPool) - if (config_use_vertical_biochemistry) then + if (config_use_vertical_tracers) then call MPAS_pool_get_array(biogeochemistryPool, "primaryProduction", primaryProduction) call MPAS_pool_get_array(biogeochemistryPool, "totalChlorophyll", totalChlorophyll) call MPAS_pool_get_array(biogeochemistryPool, "netSpecificAlgalGrowthRate", netSpecificAlgalGrowthRate) @@ -16594,7 +16551,7 @@ subroutine seaice_icepack_reinitialize_diagnostics_bgc(domain) call MPAS_pool_get_config(block % configs, "config_use_column_shortwave", config_use_column_shortwave) - if (config_use_column_biogeochemistry .or. config_use_column_shortwave) then + if (config_use_column_biogeochemistry .or. config_use_column_shortwave .or. config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistryPool) call MPAS_pool_get_array(biogeochemistryPool, "bioTracerShortwave", bioTracerShortwave) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F index ddbbaf0af2c..3aa80c43427 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F @@ -2305,7 +2305,8 @@ subroutine initialize_coupler_fields(domain) config_do_restart, & config_use_column_biogeochemistry, & config_use_column_package, & - config_use_aerosols + config_use_aerosols, & + config_use_zaerosols integer, pointer :: & nCells @@ -2402,8 +2403,9 @@ subroutine initialize_coupler_fields(domain) endif call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .or. config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry) From e09f1873484ffa3c20ad3bdc5ae1d4e16b52941a Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 13 Oct 2023 14:28:40 -0500 Subject: [PATCH 002/388] Clean-up from the merge --- components/mpas-seaice/src/column/ice_algae.F90 | 16 +++++++++++++--- .../model_forward/mpas_seaice_core_interface.F | 8 ++++---- .../mpas-seaice/src/shared/mpas_seaice_column.F | 1 + .../mpas-seaice/src/shared/mpas_seaice_icepack.F | 6 +++--- .../src/shared/mpas_seaice_initialize.F | 4 ++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/components/mpas-seaice/src/column/ice_algae.F90 b/components/mpas-seaice/src/column/ice_algae.F90 index f5c97b8f0a6..6ba380a4f04 100644 --- a/components/mpas-seaice/src/column/ice_algae.F90 +++ b/components/mpas-seaice/src/column/ice_algae.F90 @@ -2259,6 +2259,10 @@ subroutine algal_dyn (dt, & write(warning, *) 'Conservation error!' call add_warning(warning) if (tr_bgc_DON) then + write(warning, *) 'Error bound = max(puny,maxval(abs(reactb(:)))*1.0e-13_dbl_kind)' + call add_warning(warning) + write(warning, *) max(puny,maxval(abs(reactb(:)))*1.0e-13_dbl_kind) + call add_warning(warning) write(warning, *) 'dN,DONin(1), kn_bac(1),secday,dt,n_doc' call add_warning(warning) write(warning, *) dN, DONin(1),kn_bac(1),secday,dt,n_doc @@ -2272,10 +2276,16 @@ subroutine algal_dyn (dt, & call add_warning(warning) write(warning, *) dN,secday,dt,n_doc call add_warning(warning) - write(warning, *) 'reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2)' + write(warning, *) 'reactb(nlt_bgc_Nit),fr_resp' call add_warning(warning) - write(warning, *) reactb(nlt_bgc_Nit),reactb(nlt_bgc_N(1)),reactb(nlt_bgc_N(2)) + write(warning, *) reactb(nlt_bgc_Nit),fr_resp call add_warning(warning) + do k = 1,n_algae + write(warning, *) 'reactb(nlt_bgc_N(k)),fr_graze(k), grow_N(k), mort(k)' + call add_warning(warning) + write(warning, *) reactb(nlt_bgc_N(k)),fr_graze(k), grow_N(k), mort(k) + call add_warning(warning) + enddo if (tr_bgc_Am) then write(warning, *) 'reactb(nlt_bgc_Am),Am_r, Am_s' call add_warning(warning) @@ -2298,6 +2308,7 @@ subroutine algal_dyn (dt, & write(warning, *) 'DOC_r,DOC_s' call add_warning(warning) write(warning, *) DOC_r(k),DOC_s(k) + call add_warning(warning) end do do k = 1,n_dic write(warning, *) 'DICin' @@ -2312,7 +2323,6 @@ subroutine algal_dyn (dt, & call add_warning(warning) write(warning, *) DIC_r(k),DIC_s(k) end do - call add_warning(warning) write(warning, *) 'Zoo' call add_warning(warning) write(warning, *) Zoo diff --git a/components/mpas-seaice/src/model_forward/mpas_seaice_core_interface.F b/components/mpas-seaice/src/model_forward/mpas_seaice_core_interface.F index 5e83f651dab..d89cf9dd0db 100644 --- a/components/mpas-seaice/src/model_forward/mpas_seaice_core_interface.F +++ b/components/mpas-seaice/src/model_forward/mpas_seaice_core_interface.F @@ -315,14 +315,14 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{ call MPAS_pool_get_config(configPool, "config_use_column_physics", config_use_column_physics) call MPAS_pool_get_config(configPool, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) - call MPAS_pool_get_config(configPool, "config_use_column_zaerosols", config_use_zaerosols) + call MPAS_pool_get_config(configPool, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_package(packagePool, "pkgColumnPackageActive", pkgColumnPackageActive) call MPAS_pool_get_package(packagePool, "pkgColumnBiogeochemistryActive", pkgColumnBiogeochemistryActive) - pkgColumnPackageActive = config_use_column_package + pkgColumnPackageActive = config_use_column_physics pkgColumnBiogeochemistryActive = ((config_use_column_biogeochemistry .or. config_use_zaerosols) & - .and. config_use_column_package) + .and. config_use_column_physics) !pkgColumnPackageActive = .true. !pkgColumnBiogeochemistryActive = .true. @@ -494,7 +494,7 @@ subroutine setup_packages_column_physics(configPool, packagePool, ierr)!{{{ pkgColumnTracerSnowGrainRadiusActive = .false. endif - if (.not. config_use_column_biogeochemistry .and. config_use_column_package) then + if (.not. config_use_column_biogeochemistry .and. config_use_column_physics) then pkgTracerSkeletalAlgaeActive = .false. pkgTracerSkeletalNitrateActive = .false. pkgTracerSkeletalCarbonActive = .false. diff --git a/components/mpas-seaice/src/shared/mpas_seaice_column.F b/components/mpas-seaice/src/shared/mpas_seaice_column.F index 78155f0f73e..4364e808a8e 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_column.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_column.F @@ -14830,6 +14830,7 @@ subroutine seaice_column_reinitialize_diagnostics_bgc(domain) bioTracerShortwave logical, pointer :: & + config_use_column_physics, & config_use_column_biogeochemistry, & config_use_column_shortwave, & config_use_column_package, & diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 72970727128..050ec91c074 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -12502,8 +12502,8 @@ subroutine init_icepack_package_configs(domain) grid_o_t_in = config_biogrid_top_molecular_sublayer, & !initbio_frac_in = config_new_ice_fraction_biotracer, & !frazil_scav_in = config_fraction_biotracer_in_frazil, & - grid_oS_in = config_zsalinity_molecular_sublayer, & - l_skS_in = config_zsalinity_gravity_drainage_scale, & + !grid_oS_in = config_zsalinity_molecular_sublayer, & + !l_skS_in = config_zsalinity_gravity_drainage_scale, & phi_snow_in = config_snow_porosity_at_ice_surface, & !ratio_Si2N_diatoms_in = config_ratio_Si_to_N_diatoms, & !ratio_Si2N_sp_in = config_ratio_Si_to_N_small_plankton, & @@ -15942,7 +15942,7 @@ subroutine seaice_icepack_reinitialize_diagnostics_bgc(domain) logical, pointer :: & config_use_column_biogeochemistry, & config_use_column_shortwave, & - config_use_column_package, & + config_use_column_physics, & config_use_vertical_tracers, & config_use_vertical_zsalinity, & config_use_zaerosols diff --git a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F index 87245eaecc8..e2ca0dbf221 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F @@ -2577,10 +2577,10 @@ subroutine initialize_coupler_fields(domain) maxAerosolType, & nZBGCTracers - logical, pointer :: & + logical, pointer :: & config_do_restart, & config_use_column_biogeochemistry, & - config_use_column_package, & + config_use_column_physics, & config_use_aerosols, & config_use_zaerosols From e5b6cda92fdee34f2f7eab102c9539ce28494546 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 13 Oct 2023 15:02:50 -0500 Subject: [PATCH 003/388] Modified algal growth by mistake in merge. Changed back to original formulation. --- components/mpas-seaice/src/column/ice_algae.F90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/mpas-seaice/src/column/ice_algae.F90 b/components/mpas-seaice/src/column/ice_algae.F90 index 6ba380a4f04..c450e8ee059 100644 --- a/components/mpas-seaice/src/column/ice_algae.F90 +++ b/components/mpas-seaice/src/column/ice_algae.F90 @@ -2016,9 +2016,8 @@ subroutine algal_dyn (dt, & N_r_g = graze(k) * dt N_r_r = resp(k) * dt N_r_mo = mort(k) * dt - N_s(k) = (c1- fr_resp - fr_graze(k)) * grow_N(k) *dt !N_s_p - N_r(k) = mort(k) * dt !N_r_g + N_r_mo + N_r_r - + N_s(k) = N_s_p !(c1- fr_resp - fr_graze(k)) * grow_N(k) *dt + N_r(k) = N_r_g + N_r_mo + N_r_r !mort(k) * dt graze_N = graze_N + graze(k) graze_C = graze_C + R_C2N(k)*graze(k) mort_N = mort_N + mort(k) From 4b776941b3eb936f43e83e2a6f3092ed01373489 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Tue, 24 Oct 2023 13:15:07 -0500 Subject: [PATCH 004/388] Adds the interface for icepack zaerosols and zbgc -bugfix in carbon conservation - Fluxes scaled by aicen not aicen_init -puts snow aerosols into ice rather than ocean for small snow volumes -Changes vertical z-tracer flags so that aerosols and bgc are turned on separately: 1) config_use_column_biogeochemistry indicates biogeochemical tracers are on 2) config_use_zaerosols indicates dust and black carbon are on BFB in the default configuration. nonBFB with zaerosols or column_biogeochemistry --- .../mpas-seaice/src/column/ice_aerosol.F90 | 20 ++- .../mpas-seaice/src/column/ice_algae.F90 | 22 ++- .../mpas-seaice/src/column/ice_warnings.F90 | 2 +- .../mpas-seaice/src/column/ice_zbgc.F90 | 6 +- .../src/shared/mpas_seaice_column.F | 22 ++- .../src/shared/mpas_seaice_icepack.F | 144 ++++++------------ 6 files changed, 101 insertions(+), 115 deletions(-) diff --git a/components/mpas-seaice/src/column/ice_aerosol.F90 b/components/mpas-seaice/src/column/ice_aerosol.F90 index c3e6a9d0bf2..a4a270713a8 100644 --- a/components/mpas-seaice/src/column/ice_aerosol.F90 +++ b/components/mpas-seaice/src/column/ice_aerosol.F90 @@ -580,17 +580,21 @@ subroutine update_snow_bgc (dt, nblyr, & if (dzssl_new .lt. hs_ssl_min) then ! Put atm BC/dust flux directly into the sea ice do k=1,nbtrcr - flux_bio(k) = flux_bio(k) + & + flux_bio_o(k) = flux_bio(k) + if (hilyr .lt. hs_ssl_min) then + flux_bio(k) = flux_bio(k) + & (trcrn(bio_index(k)+ nblyr+1)*dzssl+ & trcrn(bio_index(k)+ nblyr+2)*dzint)/dt - trcrn(bio_index(k) + nblyr+1) = c0 - trcrn(bio_index(k) + nblyr+2) = c0 - if (hilyr .lt. hs_ssl_min) then flux_bio(k) = flux_bio(k) + flux_bio_atm(k) else + zbgc_snow(k) = zbgc_snow(k) + & + (trcrn(bio_index(k)+ nblyr+1)*dzssl+ & + trcrn(bio_index(k)+ nblyr+2)*dzint) zbgc_atm(k) = zbgc_atm(k) & + flux_bio_atm(k)*dt end if + trcrn(bio_index(k) + nblyr+1) = c0 + trcrn(bio_index(k) + nblyr+2) = c0 enddo else @@ -616,7 +620,7 @@ subroutine update_snow_bgc (dt, nblyr, & end if if (dzint <= puny) then do k = 1,nbtrcr - flux_bio(k) = flux_bio(k) + (aerosno(k,2) + aerosno(k,1))/dt + zbgc_snow(k) = zbgc_snow(k) + (aerosno(k,2) + aerosno(k,1)) aerosno(k,2) = c0 aerosno(k,1) = c0 end do @@ -636,6 +640,7 @@ subroutine update_snow_bgc (dt, nblyr, & dzssl = dzssl - dz + fsnow/rhos*dt dzint = dzint + dz end if + if (dzssl <= puny) then do k = 1,nbtrcr aerosno(k,2) = aerosno(k,2) + aerosno(k,1) @@ -644,7 +649,7 @@ subroutine update_snow_bgc (dt, nblyr, & end if if (dzint <= puny) then do k = 1,nbtrcr - flux_bio(k) = flux_bio(k) + (aerosno(k,2) + aerosno(k,1))/dt + zbgc_snow(k) = zbgc_snow(k) + (aerosno(k,2) + aerosno(k,1)) aerosno(k,2) = c0 aerosno(k,1) = c0 end do @@ -664,7 +669,7 @@ subroutine update_snow_bgc (dt, nblyr, & sloss2 = kscavz(bio_index_o(k))*aerosno(k,2) & *max(-dhs_melts-dzssl,c0)/dzint aerosno(k,2) = max(c0,aerosno(k,2) - sloss2) - flux_bio(k) = flux_bio(k) + (sloss1+sloss2)/dt ! all not scavenged ends in ocean + zbgc_snow(k) = zbgc_snow(k) + (sloss1+sloss2) ! all not scavenged ends in ice enddo ! update snow thickness @@ -795,6 +800,7 @@ subroutine update_snow_bgc (dt, nblyr, & else if (aerotot(k) > c0) then aero_cons(k) = aero_cons(k)/aerotot(k) end if + if (aero_cons(k) > puny .or. zbgc_snow(k) + zbgc_atm(k) < c0) then write(warning,*) 'Conservation failure: aerosols in snow' call add_warning(warning) diff --git a/components/mpas-seaice/src/column/ice_algae.F90 b/components/mpas-seaice/src/column/ice_algae.F90 index c450e8ee059..ec7afff6073 100644 --- a/components/mpas-seaice/src/column/ice_algae.F90 +++ b/components/mpas-seaice/src/column/ice_algae.F90 @@ -347,8 +347,12 @@ subroutine zbio (dt, nblyr, & call add_warning(warning) write(warning,*) Tot_BGC_i(mm) + flux_bio_atm(mm)*dt - flux_bion(mm)*dt call add_warning(warning) - !l_stop = .true. - !stop_label = "carbon conservation in ice_algae.F90" + write(warning,*) 'hbri, hbri_old' + call add_warning(warning) + write(warning,*) hbri, hbri_old + call add_warning(warning) + l_stop = .true. + stop_label = "carbon conservation in ice_algae.F90" enddo endif endif @@ -1021,7 +1025,7 @@ subroutine z_biogeochemistry (n_cat, dt, & Nquota_I = 0.0408_dbl_kind, & ! Intercept in N quota to cell volume fit f_s = p1, & ! fracton of sites available for saturation f_a = 0.3_dbl_kind, & !c1 , & ! fraction of collector available for attachment - f_v = 0.7854 ! fraction of algal coverage on area availabel for attachment + f_v = 0.7854_dbl_kind ! fraction of algal coverage on area availabel for attachment ! 4(pi r^2)/(4r)^2 [Johnson et al, 1995, water res. research] integer, parameter :: & @@ -1413,8 +1417,16 @@ subroutine z_biogeochemistry (n_cat, dt, & call add_warning(warning) write(warning, *) m, nlt_bgc_DIC(1), bio_tmp, react(k,m) call add_warning(warning) - flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri_old/dt + write(warning,*)'flux_bio(m) Initial, hbri_old, dz(k)' + call add_warning(warning) + write(warning,*) flux_bio(m), hbri_old, dz(k) + call add_warning(warning) + flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri/dt bio_tmp = c0 + write(warning,*) 'flux_bio(m)' + call add_warning(warning) + write(warning,*) flux_bio(m) + call add_warning(warning) end if if (m .eq. nlt_bgc_Nit) then initcons_mobile(k) = max(c0,(biomat_brine(k,m)-nitrification(k) + & @@ -1442,7 +1454,7 @@ subroutine z_biogeochemistry (n_cat, dt, & l_stop = .true. stop_label = 'C in algal_dyn not conserved' elseif (abs(bio_tmp) < puny) then - flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri_old/dt + flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri/dt bio_tmp = c0 elseif (bio_tmp > 1.0e8_dbl_kind) then write(warning, *) 'very large bgc value' diff --git a/components/mpas-seaice/src/column/ice_warnings.F90 b/components/mpas-seaice/src/column/ice_warnings.F90 index a3424c176bb..091c8b2be94 100644 --- a/components/mpas-seaice/src/column/ice_warnings.F90 +++ b/components/mpas-seaice/src/column/ice_warnings.F90 @@ -82,7 +82,7 @@ subroutine add_warning(warning) deallocate(warningsTmp) endif - + endif ! increase warning number diff --git a/components/mpas-seaice/src/column/ice_zbgc.F90 b/components/mpas-seaice/src/column/ice_zbgc.F90 index 1f1c6a7d910..e8cef6dcad9 100644 --- a/components/mpas-seaice/src/column/ice_zbgc.F90 +++ b/components/mpas-seaice/src/column/ice_zbgc.F90 @@ -679,9 +679,9 @@ subroutine merge_bgc_fluxes (dt, nblyr, & snow_bio_net(mm) = snow_bio_net(mm) & + trcrn(bio_index(mm)+nblyr+1)*dvssl & + trcrn(bio_index(mm)+nblyr+2)*dvint - flux_bio (mm) = flux_bio (mm) + flux_bion (mm)*aice_init - zbgc_snow (mm) = zbgc_snow(mm) + zbgc_snown(mm)*aice_init/dt - zbgc_atm (mm) = zbgc_atm (mm) + zbgc_atmn (mm)*aice_init/dt + flux_bio (mm) = flux_bio (mm) + flux_bion (mm)*aicen + zbgc_snow (mm) = zbgc_snow(mm) + zbgc_snown(mm)*aicen/dt + zbgc_atm (mm) = zbgc_atm (mm) + zbgc_atmn (mm)*aicen/dt enddo ! mm ! diagnostics : mean cell bio interface grid profiles diff --git a/components/mpas-seaice/src/shared/mpas_seaice_column.F b/components/mpas-seaice/src/shared/mpas_seaice_column.F index 4364e808a8e..cfebdab2e20 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_column.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_column.F @@ -2664,7 +2664,8 @@ subroutine column_snow(domain) logical, pointer :: & config_use_effective_snow_density, & config_use_snow_grain_radius, & - config_use_column_biogeochemistry + config_use_column_biogeochemistry, & + config_use_zaerosols real(kind=RKIND), dimension(:,:,:), pointer :: & snowIceMass, & @@ -2755,6 +2756,7 @@ subroutine column_snow(domain) call MPAS_pool_get_config(block % configs, "config_wind_compaction_factor", config_wind_compaction_factor) call MPAS_pool_get_config(block % configs, "config_snow_redistribution_factor", config_snow_redistribution_factor) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve) call MPAS_pool_get_dimension(block % dimensions, "nCategories", nCategories) @@ -2798,7 +2800,7 @@ subroutine column_snow(domain) call MPAS_pool_get_array(ocean_fluxes, "oceanHeatFlux", oceanHeatFlux) setGetPhysicsTracers = .true. - setGetBGCTracers = config_use_column_biogeochemistry + setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) ! code abort abortFlag = .false. @@ -10326,10 +10328,20 @@ subroutine check_column_package_configs(domain) messageType=MPAS_LOG_CRIT) endif - ! check that vertical bio tracers and not used with skeletal bio tracers - if (config_use_vertical_tracers .and. config_use_skeletal_biochemistry) then + ! check that vertical bio tracers use brine height + if ((config_use_vertical_biochemistry .or. config_use_zaerosols) .and. & + (.not. config_use_brine .or. .not. config_use_vertical_tracers )) then + call mpas_log_write(& + "check_column_package_configs: vertical biochemistry and zaerosols require " //& + "config_use_brine and config_use_vertical_tracer = true", & + messageType=MPAS_LOG_CRIT) + endif + + ! check that brine height is used with either aerosols or bgc + if (config_use_brine .and. & + (.not. config_use_column_biogeochemistry .and. .not. config_use_zaerosols)) then call mpas_log_write(& - "check_column_package_configs: vertical bio tracers and skeletal bio tracers cannot both be true", & + "check_column_package_configs: brine tracer must be used with vertical tracers - config_use_column_biogeochemistry and/or config_use_zaerosols equal to true", & messageType=MPAS_LOG_CRIT) endif diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 050ec91c074..2c26fd08f40 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -2990,7 +2990,9 @@ subroutine column_radiation(domain, clock, lInitialization) iceBodyAerosol, & brineFraction, & bioTracerShortwave, & - snowGrainRadius + snowGrainRadius, & + verticalAerosolsConc, & + verticalAlgaeConc real(kind=RKIND), pointer :: & dayOfNextShortwaveCalculation ! needed for CESM like coupled simulations @@ -3060,11 +3062,11 @@ subroutine column_radiation(domain, clock, lInitialization) call MPAS_pool_get_config(block % configs, "config_dt", config_dt) call MPAS_pool_get_config(block % configs, "config_snow_redistribution_scheme", config_snow_redistribution_scheme) - call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) - call MPAS_pool_get_dimension(mesh, "nCategories", nCategories) - call MPAS_pool_get_dimension(mesh, "nIceLayers", nIceLayers) - call MPAS_pool_get_dimension(mesh, "nSnowLayers", nSnowLayers) - call MPAS_pool_get_dimension(mesh, "nAerosols", nAerosols) + call MPAS_pool_get_dimension(block % dimensions, "nCellsSolve", nCellsSolve) + call MPAS_pool_get_dimension(block % dimensions, "nCategories", nCategories) + call MPAS_pool_get_dimension(block % dimensions, "nIceLayers", nIceLayers) + call MPAS_pool_get_dimension(block % dimensions, "nSnowLayers", nSnowLayers) + call MPAS_pool_get_dimension(block % dimensions, "nAerosols", nAerosols) call MPAS_pool_get_dimension(block % dimensions, "nAlgae", nAlgae) call MPAS_pool_get_dimension(block % dimensions, "nBioLayers", nBioLayers) call MPAS_pool_get_dimension(block % dimensions, "nzAerosols", nzAerosols) @@ -3087,6 +3089,8 @@ subroutine column_radiation(domain, clock, lInitialization) call MPAS_pool_get_array(tracers, "iceBodyAerosol", iceBodyAerosol, 1) call MPAS_pool_get_array(tracers, "brineFraction", brineFraction, 1) call MPAS_pool_get_array(tracers, "snowGrainRadius", snowGrainRadius, 1) + call MPAS_pool_get_array(tracers, "verticalAlgaeConc", verticalAlgaeConc, 1) + call MPAS_pool_get_array(tracers, "verticalAerosolsConc", verticalAerosolsConc, 1) call MPAS_pool_get_array(atmos_coupling, "shortwaveVisibleDirectDown", shortwaveVisibleDirectDown) call MPAS_pool_get_array(atmos_coupling, "shortwaveVisibleDiffuseDown", shortwaveVisibleDiffuseDown) @@ -3137,6 +3141,7 @@ subroutine column_radiation(domain, clock, lInitialization) allocate(index_shortwaveAerosol(maxAerosolType)) allocate(index_verticalAerosolsConc(maxAerosolType)) allocate(index_algaeConc(nAlgae)) + if (.not. config_use_zaerosols) then index_shortwaveAerosol(1:maxAerosolType) = 1 index_verticalAerosolsConc(1:maxAerosolType) = 1 @@ -3146,6 +3151,7 @@ subroutine column_radiation(domain, clock, lInitialization) index_verticalAerosolsConc(iAerosol) = ciceTracerObject % index_verticalAerosolsConc(iAerosol) enddo endif + if (.not. config_use_column_biogeochemistry) then index_algaeConc(1:nAlgae) = 1 else @@ -3190,10 +3196,6 @@ subroutine column_radiation(domain, clock, lInitialization) lonCellColumn = lonCell(iCell) if (lonCellColumn > seaicePi) lonCellColumn = lonCellColumn - 2.0_RKIND * seaicePi - ! set the category tracer array - call set_cice_tracer_array_category(block, ciceTracerObject, & - tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - call icepack_step_radiation(& dt=config_dt, & swgrid=verticalShortwaveGrid(:), & @@ -3208,8 +3210,8 @@ subroutine column_radiation(domain, clock, lInitialization) hpndn=pondDepth(1,:,iCell), & ipndn=pondLidThickness(1,:,iCell), & aeron=aerosolsArray, & - bgcNn=tracerArrayCategory(index_algaeConc(:),:), & - zaeron=tracerArrayCategory(index_verticalAerosolsConc(:),:), & + bgcNn=verticalAlgaeConc(:,:,iCell), & + zaeron=verticalAerosolsConc(:,:,iCell), & trcrn_bgcsw=bioTracerShortwave(:,:,iCell), & TLAT=latCell(iCell), & TLON=lonCellColumn, & @@ -3249,10 +3251,6 @@ subroutine column_radiation(domain, clock, lInitialization) l_print_point=.false., & initonly=lInitialization) - ! set the category tracer array - call get_cice_tracer_array_category(block, ciceTracerObject, & - tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - enddo ! iCell deallocate(snow_grain_radius) @@ -3603,7 +3601,6 @@ subroutine column_biogeochemistry(domain) ! variables real(kind=RKIND), dimension(:), pointer :: & - rayleighCriteriaReal, & netNitrateUptake, & netAmmoniumUptake, & totalVerticalSalinity, & @@ -3722,7 +3719,6 @@ subroutine column_biogeochemistry(domain) logical :: & abortFlag, & - rayleighCriteria, & setGetPhysicsTracers, & setGetBGCTracers, & checkCarbon @@ -3791,7 +3787,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "brineBottomChange", brineBottomChange) call MPAS_pool_get_array(biogeochemistry, "brineTopChange", brineTopChange) call MPAS_pool_get_array(biogeochemistry, "bioPorosity", bioPorosity) - call MPAS_pool_get_array(biogeochemistry, "rayleighCriteriaReal", rayleighCriteriaReal) call MPAS_pool_get_array(biogeochemistry, "biologyGrid", biologyGrid) call MPAS_pool_get_array(biogeochemistry, "interfaceBiologyGrid", interfaceBiologyGrid) call MPAS_pool_get_array(biogeochemistry, "interfaceGrid", interfaceGrid) @@ -3878,8 +3873,8 @@ subroutine column_biogeochemistry(domain) atmosBioFluxes(:,:) = 0.0_RKIND - !$omp parallel do default(shared) private(iCategory,iBioTracers,iAlgae, rayleighCriteria, & - !$omp& rayleighCriteriaReal) firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & + !$omp parallel do default(shared) private(iCategory,iBioTracers,iAlgae) & + !$omp& firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & !$omp& atmosDustFlux, bioShortwaveFluxCell, newlyFormedIce) ! do iCell = 1, nCellsSolve @@ -3889,7 +3884,6 @@ subroutine column_biogeochemistry(domain) brineHeightCatInitial(iCategory) = brineFraction(1,iCategory,iCell) * & iceVolumeCategoryInitial(iCategory,iCell)/(iceAreaCategoryInitial(iCategory,iCell) + seaicePuny) enddo ! iCategory - rayleighCriteria = (rayleighCriteriaReal(iCell) > 0.5_RKIND) !update ocean concentrations fields and atmospheric fluxes into allocated array #ifdef coupled @@ -3972,7 +3966,6 @@ subroutine column_biogeochemistry(domain) snow_bio_net=totalVerticalBiologySnow(:,iCell), & totalChla=totalChlorophyll(iCell), & fswthrun=penetratingShortwaveFlux(:,iCell), & - Rayleigh_criteria=rayleighCriteria, & bgrid=biologyGrid, & igrid=interfaceBiologyGrid, & icgrid=interfaceGrid, & @@ -4068,8 +4061,6 @@ subroutine column_biogeochemistry(domain) if (newlyFormedIceLogical(iCategory)) newlyFormedIce(iCategory,iCell) = 1 enddo ! iCategory - if (.not. rayleighCriteria) rayleighCriteriaReal(iCell) = 0.0_RKIND - enddo ! iCell ! code abort @@ -5585,8 +5576,8 @@ subroutine seaice_icepack_init_ocean_conc(& carbonToNitrogenRatioAlgae, & carbonToNitrogenRatioDON) - use ice_colpkg, only: & - colpkg_init_ocean_conc + use icepack_intfc, only: & + icepack_init_ocean_bio integer, intent(in) :: & maxDICType, & @@ -5615,26 +5606,26 @@ subroutine seaice_icepack_init_ocean_conc(& carbonToNitrogenRatioAlgae, & ! carbon to nitrogen ratio for algae carbonToNitrogenRatioDON ! nitrogen to carbon ratio for proteins - call colpkg_init_ocean_conc(& - oceanAmmoniumConc, & - oceanDMSPConc, & - oceanDMSConc, & - oceanAlgaeConc, & - oceanDOCConc, & - oceanDICConc, & - oceanDONConc, & - oceanDissolvedIronConc, & - oceanParticulateIronConc, & - oceanHumicsConc, & - oceanNitrateConc, & - oceanSilicateConc,& - oceanZAerosolConc, & - maxDICType, & - maxDONType, & - maxIronType, & - maxAerosolType, & - carbonToNitrogenRatioAlgae, & - carbonToNitrogenRatioDON) + call icepack_init_ocean_bio(& + amm=oceanAmmoniumConc, & + dmsp=oceanDMSPConc, & + dms=oceanDMSConc, & + algalN=oceanAlgaeConc, & + doc=oceanDOCConc, & + dic=oceanDICConc, & + don=oceanDONConc, & + fed=oceanDissolvedIronConc, & + fep=oceanParticulateIronConc, & + hum=oceanHumicsConc, & + nit=oceanNitrateConc, & + sil=oceanSilicateConc,& + zaeros=oceanZAerosolConc, & + max_dic=maxDICType, & + max_don=maxDONType, & + max_fe=maxIronType, & + max_aero=maxAerosolType, & + CToN=carbonToNitrogenRatioAlgae, & + CToN_DON=carbonToNitrogenRatioDON) end subroutine seaice_icepack_init_ocean_conc @@ -9560,10 +9551,10 @@ subroutine check_column_package_configs(domain) ! check biogeochemistry flags: ! if (.not. config_use_column_biogeochemistry .and. (config_use_brine .or. config_use_vertical_zsalinity .or. & - if (.not. config_use_column_biogeochemistry .and. (config_use_brine .or. & - config_use_vertical_biochemistry .or. config_use_shortwave_bioabsorption .or. config_use_vertical_tracers .or. & - config_use_skeletal_biochemistry .or. config_use_nitrate .or. config_use_carbon .or. config_use_chlorophyll .or. & - config_use_ammonium .or. config_use_silicate .or. config_use_DMS .or. config_use_nonreactive .or. config_use_humics .or. & + if (.not. config_use_column_biogeochemistry .and. (config_use_vertical_biochemistry .or. & + config_use_skeletal_biochemistry .or. config_use_nitrate .or. config_use_carbon .or. & + config_use_chlorophyll .or. config_use_ammonium .or. config_use_silicate .or. & + config_use_DMS .or. config_use_nonreactive .or. config_use_humics .or. & config_use_DON .or. config_use_iron)) then call mpas_log_write(& "check_column_package_configs: config_use_column_biogeochemistry = false. "//& @@ -9595,6 +9586,14 @@ subroutine check_column_package_configs(domain) messageType=MPAS_LOG_CRIT) endif + ! check that brine height is used with either aerosols or bgc + if (config_use_brine .and. & + (.not. config_use_column_biogeochemistry .and. .not. config_use_zaerosols)) then + call mpas_log_write(& + "check_column_package_configs: brine tracer must be used with vertical tracers - config_use_column_biogeochemistry and/or config_use_zaerosols equal to true", & + messageType=MPAS_LOG_CRIT) + endif + ! check that the shortwave scheme and bioabsorption is consistent if (config_use_shortwave_bioabsorption .and. .not. (trim(config_shortwave_type(1:4)) == "dEdd")) then call mpas_log_write(& @@ -14662,7 +14661,6 @@ end subroutine seaice_column_reinitialize_oceanic_fluxes subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) - !use ice_colpkg, only: colpkg_init_zbgc use icepack_intfc, only: icepack_init_zbgc type(domain_type), intent(in) :: & @@ -15207,11 +15205,6 @@ end subroutine init_column_tracer_object_for_biogeochemistry subroutine init_column_biogeochemistry_profiles(domain, tracerObject) - !use ice_colpkg, only: & - ! colpkg_init_bgc, & - ! colpkg_init_hbrine, & - ! colpkg_init_zsalinity - use icepack_intfc, only: & icepack_init_bgc, & icepack_init_hbrine, & @@ -15256,7 +15249,6 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) biologyGrid, & ! bgrid verticalShortwaveGrid, & ! swgrid interfaceGrid, & ! icgrid - rayleighCriteriaReal, & DOCPoolFractions real(kind=RKIND), dimension(:,:), pointer :: & @@ -15298,7 +15290,6 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) logical :: & abortFlag, & - rayleighCriteria, & setGetPhysicsTracers, & setGetBGCTracers @@ -15337,7 +15328,6 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) call MPAS_pool_get_array(biogeochemistry, "bioTracerShortwave", bioTracerShortwave) call MPAS_pool_get_array(biogeochemistry, "interfaceBiologyGrid", interfaceBiologyGrid) call MPAS_pool_get_array(biogeochemistry, "interfaceGrid", interfaceGrid) - call MPAS_pool_get_array(biogeochemistry, "rayleighCriteriaReal", rayleighCriteriaReal) call MPAS_pool_get_array(biogeochemistry, "verticalGrid", verticalGrid) call MPAS_pool_get_array(biogeochemistry, "biologyGrid", biologyGrid) call MPAS_pool_get_array(biogeochemistry, "verticalShortwaveGrid", verticalShortwaveGrid) @@ -17409,40 +17399,6 @@ subroutine seaice_total_carbon_content_category(block,totalCarbonContentCategory end subroutine seaice_total_carbon_content_category -!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -!----------------------------------------------------------------------- -! Warning messages -!----------------------------------------------------------------------- - -!echmod: remove this subroutine and all calls to it - - subroutine column_write_warnings(logAsErrors) - - use ice_colpkg, only: colpkg_get_warnings - - character(len=strKINDWarnings), dimension(:), allocatable :: & - warnings - - logical, intent(in) :: & - logAsErrors - - integer :: & - iWarning - - call colpkg_get_warnings(warnings) - - if (logAsErrors) then - do iWarning = 1, size(warnings) - call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_ERR) - enddo ! iWarning - else - do iWarning = 1, size(warnings) - call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_WARN) - enddo ! iWarning - endif - - end subroutine column_write_warnings - !----------------------------------------------------------------------- subroutine seaice_icepack_write_warnings(logAsErrors) From fb48cef43718554e736a903685a32b282ba90fcd Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Tue, 31 Oct 2023 15:29:58 -0500 Subject: [PATCH 005/388] Removed init_column_package_tracer_indices from mpas_seaice_icepack This column_package subroutine was accidentally added during the merge. BFB --- components/mpas-seaice/src/icepack | 2 +- .../src/shared/mpas_seaice_icepack.F | 218 ------------------ 2 files changed, 1 insertion(+), 219 deletions(-) diff --git a/components/mpas-seaice/src/icepack b/components/mpas-seaice/src/icepack index 96f2fc707fc..37a6f97a4ea 160000 --- a/components/mpas-seaice/src/icepack +++ b/components/mpas-seaice/src/icepack @@ -1 +1 @@ -Subproject commit 96f2fc707fc743d7ce6eb8f543bd449a35a1a649 +Subproject commit 37a6f97a4ea83d37a214b8dcde5d3630fe3a3316 diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 2c26fd08f40..79f5452c730 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -9790,224 +9790,6 @@ subroutine init_icepack_package_tracer_sizes(domain, tracerObject) end subroutine init_icepack_package_tracer_sizes -!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -! -! init_column_package_tracer_indices -! -!> \brief -!> \author Adrian K. Turner, LANL -!> \date 5th Feburary 2015 -!> \details -!> -! -!----------------------------------------------------------------------- - - subroutine init_column_package_tracer_indices(tracerObject) - - !use ice_colpkg_tracers, only: & - ! nt_Tsfc, & ! ice/snow temperature - ! nt_qice, & ! volume-weighted ice enthalpy (in layers) - ! nt_qsno, & ! volume-weighted snow enthalpy (in layers) - ! nt_sice, & ! volume-weighted ice bulk salinity (CICE grid layers) - ! nt_fbri, & ! volume fraction of ice with dynamic salt (hinS/vicen*aicen) - ! nt_iage, & ! volume-weighted ice age - ! nt_FY, & ! area-weighted first-year ice area - ! nt_alvl, & ! level ice area fraction - ! nt_vlvl, & ! level ice volume fraction - ! nt_apnd, & ! melt pond area fraction - ! nt_hpnd, & ! melt pond depth - ! nt_ipnd, & ! melt pond refrozen lid thickness - ! nt_aero, & ! starting index for aerosols in ice - ! nt_smice, & ! snow ice mass - ! nt_smliq, & ! snow liquid mass - ! nt_rsnw, & ! snow grain radius - ! nt_rhos, & ! snow density tracer - ! nt_fbri, & ! volume fraction of ice with dynamic salt (hinS/vicen*aicen) - ! nt_bgc_Nit, & ! nutrients - ! nt_bgc_Am, & ! - ! nt_bgc_Sil, & ! - ! nt_bgc_DMSPp, & ! trace gases (skeletal layer) - ! nt_bgc_DMSPd, & ! - ! nt_bgc_DMS, & ! - ! nt_bgc_PON, & ! zooplankton and detritus - ! nt_bgc_hum, & ! humic material - ! ! bio layer indicess - ! nlt_bgc_Nit, & ! nutrients - ! nlt_bgc_Am, & ! - ! nlt_bgc_Sil, & ! - ! nlt_bgc_DMSPp, & ! trace gases (skeletal layer) - ! nlt_bgc_DMSPd, & ! - ! nlt_bgc_DMS, & ! - ! nlt_bgc_PON, & ! zooplankton and detritus - ! nlt_bgc_hum, & ! humic material - ! nlt_chl_sw, & ! points to total chla in trcrn_sw - ! nt_zbgc_frac, & ! fraction of tracer in the mobile phase - ! nt_bgc_S, & ! Bulk salinity in fraction ice with dynamic salinity (Bio grid) - ! nt_bgc_N, & ! diatoms, phaeocystis, pico/small - ! nt_bgc_C, & ! diatoms, phaeocystis, pico/small - ! nt_bgc_chl, & ! diatoms, phaeocystis, pico/small - ! nlt_bgc_N, & ! diatoms, phaeocystis, pico/small - ! nlt_bgc_C, & ! diatoms, phaeocystis, pico/small - ! nlt_bgc_chl, & ! diatoms, phaeocystis, pico/small - ! nt_bgc_DOC, & ! dissolved organic carbon - ! nlt_bgc_DOC, & ! dissolved organic carbon - ! nt_bgc_DON, & ! dissolved organic nitrogen - ! nlt_bgc_DON, & ! dissolved organic nitrogen - ! nt_bgc_DIC, & ! dissolved inorganic carbon - ! nlt_bgc_DIC, & ! dissolved inorganic carbon - ! nt_bgc_Fed, & ! dissolved iron - ! nt_bgc_Fep, & ! particulate iron - ! nlt_bgc_Fed, & ! dissolved iron - ! nlt_bgc_Fep, & ! particulate iron - ! nt_zaero, & ! black carbon and other aerosols - ! nlt_zaero, & ! black carbon and other aerosols - ! nlt_zaero_sw ! black carbon and other aerosols - - use ice_colpkg, only: & - colpkg_init_tracer_indices - - type(ciceTracerObjectType), intent(in) :: & - tracerObject - - call colpkg_init_tracer_indices(& - tracerObject % index_surfaceTemperature, & - tracerObject % index_iceEnthalpy, & - tracerObject % index_snowEnthalpy, & - tracerObject % index_iceSalinity, & - tracerObject % index_brineFraction, & - tracerObject % index_iceAge, & - tracerObject % index_firstYearIceArea, & - tracerObject % index_levelIceArea, & - tracerObject % index_levelIceVolume, & - tracerObject % index_pondArea, & - tracerObject % index_pondDepth, & - tracerObject % index_pondLidThickness, & - tracerObject % index_aerosols, & - tracerObject % index_snowIceMass, & - tracerObject % index_snowLiquidMass, & - tracerObject % index_snowGrainRadius, & - tracerObject % index_snowDensity, & - tracerObject % index_verticalAerosolsConc, & - tracerObject % index_algaeConc, & - tracerObject % index_algalCarbon, & - tracerObject % index_algalChlorophyll, & - tracerObject % index_DOCConc, & - tracerObject % index_DONConc, & - tracerObject % index_DICConc, & - tracerObject % index_dissolvedIronConc, & - tracerObject % index_particulateIronConc, & - tracerObject % index_nitrateConc, & - tracerObject % index_ammoniumConc, & - tracerObject % index_silicateConc, & - tracerObject % index_DMSPpConc, & - tracerObject % index_DMSPdConc, & - tracerObject % index_DMSConc, & - tracerObject % index_humicsConc, & - tracerObject % index_nonreactiveConc, & - tracerObject % index_verticalAerosolsConcLayer, & - tracerObject % index_algaeConcLayer, & - tracerObject % index_algalCarbonLayer, & - tracerObject % index_algalChlorophyllLayer, & - tracerObject % index_DOCConcLayer, & - tracerObject % index_DONConcLayer, & - tracerObject % index_DICConcLayer, & - tracerObject % index_dissolvedIronConcLayer, & - tracerObject % index_particulateIronConcLayer, & - tracerObject % index_nitrateConcLayer, & - tracerObject % index_ammoniumConcLayer, & - tracerObject % index_silicateConcLayer, & - tracerObject % index_DMSPpConcLayer, & - tracerObject % index_DMSPdConcLayer, & - tracerObject % index_DMSConcLayer, & - tracerObject % index_humicsConcLayer, & - tracerObject % index_nonreactiveConcLayer, & - tracerObject % index_mobileFraction, & - tracerObject % index_verticalSalinity, & - tracerObject % index_chlorophyllShortwave, & - tracerObject % index_verticalAerosolsConcShortwave, & - tracerObject % nAlgaeIndex, & - tracerObject % nAlgalCarbonIndex, & - tracerObject % nAlgalChlorophyllIndex, & - tracerObject % nDOCIndex, & - tracerObject % nDONIndex, & - tracerObject % nDICIndex, & - tracerObject % nDissolvedIronIndex, & - tracerObject % nParticulateIronIndex, & - tracerObject % nzAerosolsIndex, & - tracerObject % index_LayerIndexToDataArray, & - tracerObject % index_LayerIndexToBioIndex, & - tracerObject % nBioTracers) - - !nt_Tsfc = tracerObject % index_surfaceTemperature - !nt_qice = tracerObject % index_iceEnthalpy - !nt_qsno = tracerObject % index_snowEnthalpy - !nt_sice = tracerObject % index_iceSalinity - !nt_iage = tracerObject % index_iceAge - !nt_FY = tracerObject % index_firstYearIceArea - !nt_alvl = tracerObject % index_levelIceArea - !nt_vlvl = tracerObject % index_levelIceVolume - !nt_apnd = tracerObject % index_pondArea - !nt_hpnd = tracerObject % index_pondDepth - !nt_ipnd = tracerObject % index_pondLidThickness - !nt_aero = tracerObject % index_aerosols - !nt_smice = tracerObject % index_snowIceMass - !nt_rsnw = tracerObject % index_snowGrainRadius - !nt_rhos = tracerObject % index_snowDensity - !nt_smliq = tracerObject % index_snowLiquidMass - !nt_fbri = tracerObject % index_brineFraction - !nt_zaeros = tracerObject % index_verticalAerosolsConc - !nt_bgc_N = tracerObject % index_algaeConc - !nt_bgc_C = tracerObject % index_algalCarbon - !nt_bgc_chl = tracerObject % index_algalChlorophyll - !nt_bgc_DOC = tracerObject % index_DOCConc - !nt_bgc_DON = tracerObject % index_DONConc - !nt_bgc_DIC = tracerObject % index_DICConc - !nt_bgc_Fed = tracerObject % index_dissolvedIronConc - !nt_bgc_Fep = tracerObject % index_particulateIronConc - !nt_bgc_Nit = tracerObject % index_nitrateConc - !nt_bgc_Am = tracerObject % index_ammoniumConc - !nt_bgc_Sil = tracerObject % index_silicateConc - !nt_bgc_DMSPp = tracerObject % index_DMSPpConc - !nt_bgc_DMSPd = tracerObject % index_DMSPdConc - !nt_bgc_DMS = tracerObject % index_DMSConc - !nt_bgc_hum = tracerObject % index_humicsConc - !nt_bgc_PON = tracerObject % index_nonreactiveConc - !nlt_zaero = tracerObject % index_verticalAerosolsConcLayer - !nlt_bgc_N = tracerObject % index_algaeConcLayer - !nlt_bgc_C = tracerObject % index_algalCarbonLayer - !nlt_bgc_chl = tracerObject % index_algalChlorophyllLayer - !nlt_bgc_DOC = tracerObject % index_DOCConcLayer - !nlt_bgc_DON = tracerObject % index_DONConcLayer - !nlt_bgc_DIC = tracerObject % index_DICConcLayer - !nlt_bgc_Fed = tracerObject % index_dissolvedIronConcLayer - !nlt_bgc_Fep = tracerObject % index_particulateIronConcLayer - !nlt_bgc_Nit = tracerObject % index_nitrateConcLayer - !nlt_bgc_Am = tracerObject % index_ammoniumConcLayer - !nlt_bgc_Sil = tracerObject % index_silicateConcLayer - !nlt_bgc_DMSPp = tracerObject % index_DMSPpConcLayer - !nlt_bgc_DMSPd = tracerObject % index_DMSPdConcLayer - !nlt_bgc_DMS = tracerObject % index_DMSConcLayer - !nlt_bgc_hum = tracerObject % index_humicsConcLayer - !nlt_bgc_PON = tracerObject % index_nonreactiveConcLayer - !nt_zbgc_frac = tracerObject % index_mobileFraction - !nt_zbgc_S = tracerObject % index_verticalSalinity - !nlt_chl_sw = tracerObject % index_chlorophyllShortwave - !nlt_zaero_sw = tracerObject % index_verticalAerosolsConcShortwave - !n_algae = tracerObject % nAlgaeIndex - !n_algae = tracerObject % nAlgalCarbonIndex - !n_algae = tracerObject % nAlgalChlorophyllIndex - !n_doc = tracerObject % nDOCIndex - !n_don = tracerObject % nDONIndex - !n_dic = tracerObject % nDICIndex - !n_fed = tracerObject % nDissolvedIronIndex - !n_fep = tracerObject % nParticulateIronIndex - !n_zaero = tracerObject % nzAerosolsIndex - !bio_index_o = tracerObject % index_LayerIndexToDataArray - !bio_index = tracerObject % index_LayerIndexToBioIndex - !nbtrcr = tracerObject % nBioTracers - - end subroutine init_column_package_tracer_indices - !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! ! init_icepack_package_tracer_indices From 961ca5907851d724e95ddff580e2c8a485494a54 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Thu, 16 Nov 2023 15:51:36 -0600 Subject: [PATCH 006/388] Updates mpas icepack bgc interface for optional arguments Most of the updates are for use in init_zbgc which now initializes many of the configs, indices and size declarations for bgc Contains updates to column package to make puny and accuracy consistent with carbon conservation check BFB with bgc and aerosols off --- components/mpas-seaice/src/build_options.mk | 2 +- .../mpas-seaice/src/column/ice_algae.F90 | 12 +- .../src/shared/mpas_seaice_icepack.F | 180 +++++++----------- .../src/shared/mpas_seaice_initialize.F | 4 - 4 files changed, 78 insertions(+), 120 deletions(-) diff --git a/components/mpas-seaice/src/build_options.mk b/components/mpas-seaice/src/build_options.mk index 5f2bdcfe277..0ef6fc91e5d 100644 --- a/components/mpas-seaice/src/build_options.mk +++ b/components/mpas-seaice/src/build_options.mk @@ -3,7 +3,7 @@ ifeq "$(ROOT_DIR)" "" endif EXE_NAME=seaice_model NAMELIST_SUFFIX=seaice -FCINCLUDES += -I$(ROOT_DIR)/column -I$(ROOT_DIR)/shared -I$(ROOT_DIR)/analysis_members -I$(ROOT_DIR)/model_forward +FCINCLUDES += -I$(ROOT_DIR)/icepack/columnphysics -I$(ROOT_DIR)/column -I$(ROOT_DIR)/shared -I$(ROOT_DIR)/analysis_members -I$(ROOT_DIR)/model_forward override CPPFLAGS += -DCORE_SEAICE -DUSE_SNICARHC ifneq "$(ESM)" "" override CPPFLAGS += -Dcoupled -DCCSMCOUPLED diff --git a/components/mpas-seaice/src/column/ice_algae.F90 b/components/mpas-seaice/src/column/ice_algae.F90 index ec7afff6073..78dce86e2d3 100644 --- a/components/mpas-seaice/src/column/ice_algae.F90 +++ b/components/mpas-seaice/src/column/ice_algae.F90 @@ -304,7 +304,7 @@ subroutine zbio (dt, nblyr, & carbonError = carbonInitial-carbonFlux*dt-carbonFinal - if (abs(carbonError) > accuracy * maxval ((/carbonInitial, carbonFinal/))) then + if (abs(carbonError) > max(puny,accuracy * maxval ((/carbonInitial, carbonFinal/)))) then write(warning,*) 'carbonError:', carbonError call add_warning(warning) write(warning,*) 'carbonInitial:', carbonInitial @@ -315,6 +315,8 @@ subroutine zbio (dt, nblyr, & call add_warning(warning) write(warning,*) 'accuracy * maxval ((/carbonInitial, carbonFinal/:)', accuracy * maxval ((/carbonInitial, carbonFinal/)) call add_warning(warning) + write(warning,*) 'puny', puny + call add_warning(warning) if (aicen > c0) then hsnow_f = vsnon/aicen write(warning,*) 'after z_biogeochemistry' @@ -1016,7 +1018,7 @@ subroutine z_biogeochemistry (n_cat, dt, & ! local parameters real (kind=dbl_kind), parameter :: & - accuracy = 1.0e-14_dbl_kind, & + accuracy = 1.0e-13_dbl_kind, & ! 1.0e-14_dbl_kind, & r_c = 3.0e3_dbl_kind , & ! ice crystal radius (um) r_bac= 4.7_dbl_kind , & ! diatom large radius (um) r_alg= 10.0_dbl_kind , & ! diatom small radius (um) @@ -1062,7 +1064,7 @@ subroutine z_biogeochemistry (n_cat, dt, & iphin_N(k) = iphin(k) bphin_N(1) = bphi_min - if (abs(trcrn(bio_index(m) + k-1)) < puny) then + if (abs(trcrn(bio_index(m) + k-1)) < accuracy) then flux_bio(m) = flux_bio(m) + trcrn(bio_index(m) + k-1)* hbri_old * dz(k)/dt trcrn(bio_index(m) + k-1) = c0 in_init_cons(k,m) = c0 @@ -1410,7 +1412,7 @@ subroutine z_biogeochemistry (n_cat, dt, & do m = 1,nbtrcr do k = 1,nblyr+1 ! back to bulk quantity bio_tmp = (biomat_brine(k,m) + react(k,m))*iphin_N(k) - if (tr_bgc_C .and. m .eq. nlt_bgc_DIC(1) .and. bio_tmp < -puny) then ! satisfy DIC demands from ocean + if (tr_bgc_C .and. m .eq. nlt_bgc_DIC(1) .and. bio_tmp .le. -accuracy) then ! satisfy DIC demands from ocean write(warning, *) 'DIC demand from ocean' call add_warning(warning) write(warning, *) 'm, nlt_bgc_DIC(1), bio_tmp, react(k,m):' @@ -1453,7 +1455,7 @@ subroutine z_biogeochemistry (n_cat, dt, & call add_warning(warning) l_stop = .true. stop_label = 'C in algal_dyn not conserved' - elseif (abs(bio_tmp) < puny) then + elseif (abs(bio_tmp) < accuracy) then flux_bio(m) = flux_bio(m) + bio_tmp*dz(k)*hbri/dt bio_tmp = c0 elseif (bio_tmp > 1.0e8_dbl_kind) then diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 79f5452c730..fa228e9daf3 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -3590,11 +3590,6 @@ subroutine column_biogeochemistry(domain) nBioLayers, & nBioLayersP1, & nAlgae, & - nDOC, & - nDIC, & - nDON, & - nParticulateIron, & - nDissolvedIron, & maxBCType, & maxDustType @@ -3603,7 +3598,6 @@ subroutine column_biogeochemistry(domain) real(kind=RKIND), dimension(:), pointer :: & netNitrateUptake, & netAmmoniumUptake, & - totalVerticalSalinity, & netSpecificAlgalGrowthRate, & primaryProduction, & netBrineHeight, & @@ -3759,11 +3753,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_dimension(mesh, "nBioLayers", nBioLayers) call MPAS_pool_get_dimension(mesh, "nBioLayersP1", nBioLayersP1) call MPAS_pool_get_dimension(mesh, "nAlgae", nAlgae) - call MPAS_pool_get_dimension(mesh, "nDOC", nDOC) - call MPAS_pool_get_dimension(mesh, "nDIC", nDIC) - call MPAS_pool_get_dimension(mesh, "nDON", nDON) - call MPAS_pool_get_dimension(mesh, "nParticulateIron", nParticulateIron) - call MPAS_pool_get_dimension(mesh, "nDissolvedIron", nDissolvedIron) call MPAS_pool_get_dimension(mesh, "maxBCType", maxBCType) call MPAS_pool_get_dimension(mesh, "maxDustType", maxDustType) @@ -3779,7 +3768,6 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "newlyFormedIce", newlyFormedIce) call MPAS_pool_get_array(biogeochemistry, "netNitrateUptake", netNitrateUptake) call MPAS_pool_get_array(biogeochemistry, "netAmmoniumUptake", netAmmoniumUptake) - call MPAS_pool_get_array(biogeochemistry, "totalVerticalSalinity", totalVerticalSalinity) call MPAS_pool_get_array(biogeochemistry, "totalChlorophyll", totalChlorophyll) call MPAS_pool_get_array(biogeochemistry, "netSpecificAlgalGrowthRate", netSpecificAlgalGrowthRate) call MPAS_pool_get_array(biogeochemistry, "primaryProduction", primaryProduction) @@ -3940,14 +3928,11 @@ subroutine column_biogeochemistry(domain) call icepack_warnings_clear() call icepack_biogeochemistry(& dt=config_dt, & - ntrcr=ciceTracerObject % nTracers, & - nbtrcr=ciceTracerObject % nBioTracers, & upNO=netNitrateUptake(iCell), & upNH=netAmmoniumUptake(iCell), & iDi=bioDiffusivity(:,:,iCell), & iki=bioPermeability(:,:,iCell), & zfswin=bioShortwaveFlux(:,:,iCell), & - zsal_tot=totalVerticalSalinity(iCell), & darcy_V=darcyVelocityBio(:,iCell), & grow_net=netSpecificAlgalGrowthRate(iCell), & PP_net=primaryProduction(iCell), & @@ -3973,14 +3958,7 @@ subroutine column_biogeochemistry(domain) nblyr=nBioLayers, & nilyr=nIceLayers, & nslyr=nSnowLayers, & - n_algae=nAlgae, & - n_zaero=nzAerosols, & ncat=nCategories, & - n_doc=nDOC, & - n_dic=nDIC, & - n_don=nDON, & - n_fed=nDissolvedIron, & - n_fep=nParticulateIron, & meltbn=basalIceMeltCategory(:,iCell), & melttn=surfaceIceMeltCategory(:,iCell), & congeln=congelationCategory(:,iCell), & @@ -3990,7 +3968,6 @@ subroutine column_biogeochemistry(domain) Tf=seaFreezingTemperature(iCell), & fsnow=snowfallRate(iCell), & meltsn=snowMeltCategory(:,iCell), & - !initialSalinityProfile(:,iCell), & !!!! hin_old=iceThicknessCategoryInitial(:,iCell), & flux_bio=oceanBioFluxes(:,iCell), & flux_bio_atm=atmosBioFluxes(:,iCell), & @@ -4002,7 +3979,6 @@ subroutine column_biogeochemistry(domain) aice0=openWaterArea(iCell), & trcrn=tracerArrayCategory, & vsnon_init=snowVolumeCategoryInitial(:,iCell), & - skl_bgc=config_use_skeletal_biochemistry, & flux_bion=oceanBioFluxesCategory(:,:,iCell), & bioPorosityIceCell=bgridPorosityIceCell(:,iCell), & bioSalinityIceCell=bgridSalinityIceCell(:,iCell), & @@ -5569,22 +5545,12 @@ subroutine seaice_icepack_init_ocean_conc(& oceanNitrateConc, & oceanSilicateConc,& oceanZAerosolConc, & - maxDICType, & - maxDONType, & - maxIronType, & - maxAerosolType, & carbonToNitrogenRatioAlgae, & carbonToNitrogenRatioDON) use icepack_intfc, only: & icepack_init_ocean_bio - integer, intent(in) :: & - maxDICType, & - maxDONType, & - maxIronType, & - maxAerosolType - real(kind=RKIND), intent(out):: & oceanAmmoniumConc, & ! ammonium oceanDMSPConc, & ! DMSPp @@ -5620,10 +5586,6 @@ subroutine seaice_icepack_init_ocean_conc(& nit=oceanNitrateConc, & sil=oceanSilicateConc,& zaeros=oceanZAerosolConc, & - max_dic=maxDICType, & - max_don=maxDONType, & - max_fe=maxIronType, & - max_aero=maxAerosolType, & CToN=carbonToNitrogenRatioAlgae, & CToN_DON=carbonToNitrogenRatioDON) @@ -14787,86 +14749,86 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) nblyr=nBioLayers, & nilyr=nIceLayers, & nslyr=nSnowLayers, & - n_algae=nAlgae, & - n_zaero=nzAerosols, & - n_doc=nDOC, & - n_dic=nDIC, & - n_don=nDON, & - n_fed=nDissolvedIron, & - n_fep=nParticulateIron, & + n_algae_in=nAlgae, & + n_zaero_in=nzAerosols, & + n_doc_in=nDOC, & + n_dic_in=nDIC, & + n_don_in=nDON, & + n_fed_in=nDissolvedIron, & + n_fep_in=nParticulateIron, & trcr_base=tracerObject % firstAncestorMask, & trcr_depend=tracerObject % parentIndex, & n_trcr_strata=tracerObject % ancestorNumber, & nt_strata=tracerObject % ancestorIndices, & - nbtrcr_sw=tracerObject % nBioTracersShortwave, & - tr_brine=config_use_brine, & - nt_fbri=tracerObject % index_brineFraction,& - ntrcr=tracerObject % nTracers, & - nbtrcr=tracerObject % nBioTracers, & - nt_bgc_Nit=tracerObject % index_nitrateConc, & - nt_bgc_Am=tracerObject % index_ammoniumConc, & - nt_bgc_Sil=tracerObject % index_silicateConc, & - nt_bgc_DMS=tracerObject % index_DMSConc, & - nt_bgc_PON=tracerObject % index_nonreactiveConc, & - nt_bgc_S=tracerObject % index_verticalSalinity, & - nt_bgc_N=tracerObject % index_algaeConc, & - nt_bgc_C=tracerObject % index_algalCarbon, & - nt_bgc_chl=tracerObject % index_algalChlorophyll, & - nt_bgc_DOC=tracerObject % index_DOCConc, & - nt_bgc_DON=tracerObject % index_DONConc, & - nt_bgc_DIC=tracerObject % index_DICConc, & - nt_zaero=tracerObject % index_verticalAerosolsConc, & - nt_bgc_DMSPp=tracerObject % index_DMSPpConc, & - nt_bgc_DMSPd=tracerObject % index_DMSPdConc, & - nt_bgc_Fed=tracerObject % index_dissolvedIronConc, & - nt_bgc_Fep=tracerObject % index_particulateIronConc, & - nt_zbgc_frac=tracerObject % index_mobileFraction, & - tr_bgc_Nit=config_use_nitrate, & - tr_bgc_Am=config_use_ammonium, & - tr_bgc_Sil=config_use_silicate, & - tr_bgc_DMS=config_use_DMS, & - tr_bgc_PON=config_use_nonreactive, & - tr_bgc_N=use_nitrogen, & - tr_bgc_C=config_use_carbon, & - tr_bgc_chl=config_use_chlorophyll, & - tr_bgc_DON=config_use_DON, & - tr_bgc_Fe=config_use_iron,& - tr_zaero=config_use_zaerosols, & - nlt_zaero_sw=tracerObject % index_verticalAerosolsConcShortwave, & - nlt_chl_sw=tracerObject % index_chlorophyllShortwave, & - nlt_bgc_N=tracerObject % index_algaeConcLayer, & - nlt_bgc_Nit=tracerObject % index_nitrateConcLayer, & - nlt_bgc_Am=tracerObject % index_ammoniumConcLayer, & - nlt_bgc_Sil=tracerObject % index_silicateConcLayer, & - nlt_bgc_DMS=tracerObject % index_DMSConcLayer, & - nlt_bgc_DMSPp=tracerObject % index_DMSPpConcLayer, & - nlt_bgc_DMSPd=tracerObject % index_DMSPdConcLayer, & - nlt_bgc_C=tracerObject % index_algalCarbonLayer, & - nlt_bgc_chl=tracerObject % index_algalChlorophyllLayer, & - nlt_bgc_DIC=tracerObject % index_DICConcLayer, & - nlt_bgc_DOC=tracerObject % index_DOCConcLayer, & - nlt_bgc_PON=tracerObject % index_nonreactiveConcLayer, & - nlt_bgc_DON=tracerObject % index_DONConcLayer, & - nlt_bgc_Fed=tracerObject % index_dissolvedIronConcLayer, & - nlt_bgc_Fep=tracerObject % index_particulateIronConcLayer, & - nlt_zaero=tracerObject % index_verticalAerosolsConcLayer, & - nt_bgc_hum=tracerObject % index_humicsConc, & - nlt_bgc_hum=tracerObject % index_humicsConcLayer, & - tr_bgc_hum=config_use_humics, & - skl_bgc=config_use_skeletal_biochemistry, & - z_tracers=config_use_vertical_tracers, & - dEdd_algae=config_use_shortwave_bioabsorption, & - solve_zbgc=config_use_vertical_biochemistry, & - frazil_scav_in=config_fraction_biotracer_in_frazil, & - initbio_frac_in=config_new_ice_fraction_biotracer, & + nbtrcr_sw_out=tracerObject % nBioTracersShortwave, & + tr_brine_in=config_use_brine, & + nt_fbri_out=tracerObject % index_brineFraction,& + ntrcr_out=tracerObject % nTracers, & + nbtrcr_out=tracerObject % nBioTracers, & + ntrcr_o_out=tracerObject % nTracersNotBio, & + nt_bgc_Nit_out=tracerObject % index_nitrateConc, & + nt_bgc_Am_out=tracerObject % index_ammoniumConc, & + nt_bgc_Sil_out=tracerObject % index_silicateConc, & + nt_bgc_DMS_out=tracerObject % index_DMSConc, & + nt_bgc_PON_out=tracerObject % index_nonreactiveConc, & + nt_bgc_N_out=tracerObject % index_algaeConc, & + nt_bgc_C_out=tracerObject % index_algalCarbon, & + nt_bgc_chl_out=tracerObject % index_algalChlorophyll, & + nt_bgc_DOC_out=tracerObject % index_DOCConc, & + nt_bgc_DON_out=tracerObject % index_DONConc, & + nt_bgc_DIC_out=tracerObject % index_DICConc, & + nt_zaero_out=tracerObject % index_verticalAerosolsConc, & + nt_bgc_DMSPp_out=tracerObject % index_DMSPpConc, & + nt_bgc_DMSPd_out=tracerObject % index_DMSPdConc, & + nt_bgc_Fed_out=tracerObject % index_dissolvedIronConc, & + nt_bgc_Fep_out=tracerObject % index_particulateIronConc, & + nt_zbgc_frac_out=tracerObject % index_mobileFraction, & + tr_bgc_Nit_in=config_use_nitrate, & + tr_bgc_Am_in=config_use_ammonium, & + tr_bgc_Sil_in=config_use_silicate, & + tr_bgc_DMS_in=config_use_DMS, & + tr_bgc_PON_in=config_use_nonreactive, & + tr_bgc_N_in=use_nitrogen, & + tr_bgc_C_in=config_use_carbon, & + tr_bgc_chl_in=config_use_chlorophyll, & + tr_bgc_DON_in=config_use_DON, & + tr_bgc_Fe_in=config_use_iron,& + tr_zaero_in=config_use_zaerosols, & + nlt_zaero_sw_out=tracerObject % index_verticalAerosolsConcShortwave, & + nlt_chl_sw_out=tracerObject % index_chlorophyllShortwave, & + nlt_bgc_N_out=tracerObject % index_algaeConcLayer, & + nlt_bgc_Nit_out=tracerObject % index_nitrateConcLayer, & + nlt_bgc_Am_out=tracerObject % index_ammoniumConcLayer, & + nlt_bgc_Sil_out=tracerObject % index_silicateConcLayer, & + nlt_bgc_DMS_out=tracerObject % index_DMSConcLayer, & + nlt_bgc_DMSPp_out=tracerObject % index_DMSPpConcLayer, & + nlt_bgc_DMSPd_out=tracerObject % index_DMSPdConcLayer, & + nlt_bgc_C_out=tracerObject % index_algalCarbonLayer, & + nlt_bgc_chl_out=tracerObject % index_algalChlorophyllLayer, & + nlt_bgc_DIC_out=tracerObject % index_DICConcLayer, & + nlt_bgc_DOC_out=tracerObject % index_DOCConcLayer, & + nlt_bgc_PON_out=tracerObject % index_nonreactiveConcLayer, & + nlt_bgc_DON_out=tracerObject % index_DONConcLayer, & + nlt_bgc_Fed_out=tracerObject % index_dissolvedIronConcLayer, & + nlt_bgc_Fep_out=tracerObject % index_particulateIronConcLayer, & + nlt_zaero_out=tracerObject % index_verticalAerosolsConcLayer, & + nt_bgc_hum_out=tracerObject % index_humicsConc, & + nlt_bgc_hum_out=tracerObject % index_humicsConcLayer, & + tr_bgc_hum_in=config_use_humics, & + skl_bgc_in=config_use_skeletal_biochemistry, & + z_tracers_in=config_use_vertical_tracers, & + dEdd_algae_in=config_use_shortwave_bioabsorption, & + solve_zbgc_in=config_use_vertical_biochemistry, & bio_index_o_out=tracerObject % index_LayerIndexToDataArray, & bio_index_out=tracerObject % index_LayerIndexToBioIndex, & - ntrcr_o=tracerObject % nTracersNotBio, & + frazil_scav_in=config_fraction_biotracer_in_frazil, & + initbio_frac_in=config_new_ice_fraction_biotracer, & max_algae_in=maxAlgaeType, & max_doc_in=maxDOCType, & max_dic_in=maxDICType, & max_don_in=maxDONType, & max_fe_in=maxIronType, & + max_aero_in=maxAerosolType, & ratio_Si2N_diatoms_in=config_ratio_Si_to_N_diatoms, & ratio_Si2N_sp_in=config_ratio_Si_to_N_small_plankton, & ratio_Si2N_phaeo_in=config_ratio_Si_to_N_phaeocystis, & @@ -15143,6 +15105,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1) call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP2", nBioLayersP2) call MPAS_pool_get_dimension(block % dimensions, "nShortwaveBio", nShortwaveBio) + call icepack_init_hbrine(& bgrid=biologyGrid, & igrid=interfaceBiologyGrid, & @@ -15188,11 +15151,8 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) ncat=nCategories, & nblyr=nBioLayers, & nilyr=nIceLayers, & - ntrcr_o=tracerObject % nTracersNotBio, & cgrid=verticalGrid, & igrid=interfaceBiologyGrid, & - ntrcr=tracerObject % nTracers, & - nbtrcr=tracerObject % nBiotracers, & sicen=iceSalinity(:,:,iCell), & trcrn=tracerArrayCategory(tracerObject % nTracersNotBio+1:tracerObject % nTracers,:), & sss=seaSurfaceSalinity(iCell), & diff --git a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F index e2ca0dbf221..3ae1c14aec9 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_initialize.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_initialize.F @@ -2747,10 +2747,6 @@ subroutine initialize_coupler_fields(domain) oceanNitrateConc(iCell), & oceanSilicateConc(iCell),& oceanZAerosolConc(:,iCell), & - maxDICType, & - maxDONType, & - maxIronType, & - maxAerosolType, & carbonToNitrogenRatioAlgae, & carbonToNitrogenRatioDON) From 5f73ff08a62fd0b2decd2eaa72af98746b985f4e Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Mon, 11 Dec 2023 14:57:29 -0600 Subject: [PATCH 007/388] Added bgc parameter checks Removed zsalinity references BFB --- .../src/shared/mpas_seaice_icepack.F | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index fa228e9daf3..0588cc790ee 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -14406,6 +14406,7 @@ end subroutine seaice_column_reinitialize_oceanic_fluxes subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) use icepack_intfc, only: icepack_init_zbgc + use icepack_intfc, only: icepack_query_parameters type(domain_type), intent(in) :: & domain @@ -14558,6 +14559,10 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) nTracers_temp, & iAerosols + real(kind=RKIND) :: & + rtmp1, & + rtmp2 + ! save tracer array size nTracers_temp = tracerObject % nTracers tracerObject % nTracers = tracerObject % nTracersNotBio @@ -14933,6 +14938,20 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) messageType=MPAS_LOG_CRIT, intArgs=(/nTracers_temp, tracerObject % nTracers/)) endif + call mpas_log_write(" ----- compare values after init_zbgc -----") + + rtmp1 = config_new_ice_fraction_biotracer + call icepack_query_parameters(initbio_frac_out=rtmp2) + if (rtmp1 /= rtmp2) call mpas_log_write('initbio_frac differs $r $r',realArgs=(/rtmp1,rtmp2/)) + + rtmp1 = config_rapid_mobile_to_stationary_time + call icepack_query_parameters(tau_min_out=rtmp2) + if (rtmp1 /= rtmp2) call mpas_log_write('tau_min differs $r $r',realArgs=(/rtmp1,rtmp2/)) + + rtmp1 = config_long_mobile_to_stationary_time + call icepack_query_parameters(tau_max_out=rtmp2) + if (rtmp1 /= rtmp2) call mpas_log_write('tau_max differs $r $r',realArgs=(/rtmp1,rtmp2/)) + end subroutine init_column_tracer_object_for_biogeochemistry !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| @@ -14970,10 +14989,8 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) logical, pointer :: & config_use_brine, & -! config_use_vertical_zsalinity, & !echmod deprecate config_use_vertical_tracers, & config_use_skeletal_biochemistry, & - config_do_restart_zsalinity, & config_do_restart_hbrine real(kind=RKIND), pointer :: & @@ -15041,9 +15058,7 @@ subroutine init_column_biogeochemistry_profiles(domain, tracerObject) abortMessage call MPAS_pool_get_config(domain % configs, "config_use_brine", config_use_brine) - call MPAS_pool_get_config(domain % configs, "config_do_restart_zsalinity", config_do_restart_zsalinity) call MPAS_pool_get_config(domain % configs, "config_do_restart_hbrine", config_do_restart_hbrine) -! call MPAS_pool_get_config(domain % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) !echmod deprecate call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) call MPAS_pool_get_config(domain % configs, "config_use_vertical_tracers", config_use_vertical_tracers) call MPAS_pool_get_config(domain % configs, "config_dt", config_dt) From 35bed8a9e64b31497e5fbf1bca0733b4eec7c2ab Mon Sep 17 00:00:00 2001 From: hollyhan Date: Wed, 10 Jan 2024 18:29:59 -0700 Subject: [PATCH 008/388] Add restart option when the SLM is coupled to MALI --- .../mpas-albany-landice/src/Registry.xml | 4 + .../src/mode_forward/mpas_li_bedtopo.F | 193 +++++++++++------- 2 files changed, 123 insertions(+), 74 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index 279d7fb3c0a..c4cd6df05bb 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -149,6 +149,10 @@ description="Time interval at which the sea-level model is called by MALI. The interval has to be an even multiple of the option 'config_adaptive_timestep_force_interval" possible_values="Any time interval of the format 'YYYY-MM-DD_HH:MM:SS'" /> + Date: Mon, 29 Jan 2024 21:21:10 -0700 Subject: [PATCH 009/388] Fix handling of err codes in thermal solver As written, some errors were not being handled properly, leading to runs being aborted without useful information written to an err log file. This commit writes all error related messages to the err log, sets the err code to 1, and returns control to the calling routine. --- .../src/mode_forward/mpas_li_thermal.F | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F index 4ef8ae672b8..5fa52170590 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F @@ -792,8 +792,9 @@ subroutine li_thermal_solver(domain, err) call mpas_pool_get_array(meshPool, 'deltat', deltat) if (deltat <= 0.0_RKIND) then + err = ior(err, 1) call mpas_log_write('li_thermal_solver was called with invalid deltat = $r', MPAS_LOG_ERR, realArgs=(/deltat/)) - call mpas_log_write("An error has occurred in li_thermal. Aborting...", MPAS_LOG_CRIT) + return endif @@ -1305,25 +1306,25 @@ subroutine li_thermal_solver(domain, err) mintemp = minval(temperature(:,iCell)) if (maxtemp > maxtempThreshold) then - call mpas_log_write('maxtemp > maxtempThreshold: indexToCellID=$i, maxtemp = $r', intArgs=(/indexToCellID(iCell)/), & + err = ior(err, 1) + call mpas_log_write('maxtemp > maxtempThreshold: indexToCellID=$i, maxtemp = $r', MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/), & realArgs=(/maxtemp/)) - call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/)) - call mpas_log_write('temperature:') + call mpas_log_write(' thickness = $r', MPAS_LOG_ERR, realArgs=(/thickness(iCell)/)) + call mpas_log_write(' temperature:', MPAS_LOG_ERR) do k = 1, nVertLevels - call mpas_log_write('$i $r', intArgs=(/k/), realArgs=(/temperature(k,iCell)/)) + call mpas_log_write(' $i $r', MPAS_LOG_ERR, intArgs=(/k/), realArgs=(/temperature(k,iCell)/)) enddo - call mpas_log_write("An error has occurred in li_thermal. Aborting...", MPAS_LOG_CRIT) endif if (mintemp < mintempThreshold) then - call mpas_log_write('mintemp < mintempThreshold: indexToCellID=$i, mintemp = $r', intArgs=(/indexToCellID(iCell)/), & + err = ior(err, 1) + call mpas_log_write('mintemp < mintempThreshold: indexToCellID=$i, mintemp = $r', MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/), & realArgs=(/mintemp/)) - call mpas_log_write('thickness = $r', realArgs=(/thickness(iCell)/)) - call mpas_log_write('temperature:') + call mpas_log_write(' thickness = $r', MPAS_LOG_ERR, realArgs=(/thickness(iCell)/)) + call mpas_log_write(' temperature:', MPAS_LOG_ERR) do k = 1, nVertLevels - call mpas_log_write('$i $r', intArgs=(/k/), realArgs=(/temperature(k,iCell)/)) + call mpas_log_write(' $i $r', MPAS_LOG_ERR, intArgs=(/k/), realArgs=(/temperature(k,iCell)/)) enddo - call mpas_log_write("An error has occurred in li_thermal. Aborting...", MPAS_LOG_CRIT) endif enddo ! iCell From cfa244be77fd7965af908e2cc339d5c8fbba95aa Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Mon, 29 Jan 2024 21:42:56 -0700 Subject: [PATCH 010/388] Reduce maxTempThreshold to 0.1 deg above melting temp It was previously set to 100 degC, which seems unnecessarily permissive for ice --- .../mpas-albany-landice/src/mode_forward/mpas_li_thermal.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F index 5fa52170590..96d289f400d 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F @@ -70,7 +70,7 @@ module li_thermal ! Note: kelvin_to_celsius = 273.15 (perhaps it should be called celsius_to_kelvin?) real (kind=RKIND), parameter :: & - maxtempThreshold = 100._RKIND + kelvin_to_celsius, & + maxtempThreshold = 0.1_RKIND + kelvin_to_celsius, & mintempThreshold = -100._RKIND + kelvin_to_celsius !*********************************************************************** From fd298b1420ee9e8a3015e484592d8e95aa9ac158 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 31 Jan 2024 13:50:28 -0700 Subject: [PATCH 011/388] Update basal mass balance calculation and basal water accounting Depsite comments suggesting it was the case, the existing code did not limit basal freeze on by the available basal water. This commit corrects that. It also applies the contribution of basal melting to basal water for the temperature solver, which previously was being excluded. --- .../src/mode_forward/mpas_li_thermal.F | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F index 96d289f400d..65c30096352 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F @@ -2841,15 +2841,21 @@ subroutine basal_melt_grounded_ice(& ! to the form as Eqn (66) in Aschwanden and others (2012) "An ! enthalpy formulation for glaciers and ice sheets". An extra ! term (1-w) would be more accurate. - basalWaterThickness(iCell) = basalWaterThickness(iCell) - deltat*groundedBasalMassBal(iCell) - ! TZ: allow basalWaterThickness freely accumulate here. Change it to something else for difference cases - if (basalWaterThickness(iCell) < 0.0_RKIND) then - basalWaterThickness(iCell) = 0.0_RKIND - endif else ! temperature solver groundedBasalMassBal(iCell) = -netBasalFlux / (latent_heat_ice * rhoi) ! m/s endif + ! Update basal water thickness based on melting or freezing (same for enthalpy or temperature) + if (groundedBasalMassBal(iCell) > 0.0) then + ! for freezing conditions (+SMB), limit positive BMB to the available basal water + groundedBasalMassBal(iCell) = min(groundedBasalMassBal(iCell), basalWaterThickness(iCell) / deltat) + endif + basalWaterThickness(iCell) = basalWaterThickness(iCell) - deltat*groundedBasalMassBal(iCell) + + ! negative water thickness should not occur, but if round off leads to it, set back to zero + if (basalWaterThickness(iCell) < 0.0_RKIND) then + basalWaterThickness(iCell) = 0.0_RKIND + endif endif ! ice is present and grounded From c9c13aa5d4abb80e398ba361fb362ececb82b478 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 17 May 2023 10:38:16 -0600 Subject: [PATCH 012/388] Add missing channel melt source term to mass cons eqn After further inspection, I realized that the mass conservation equation used to evolve sheet thickness is missing a source term from the production of meltwater within the channel. This is the 2nd term on the RHS of Hewitt (2013) Eq. 7, and it is missing from Eq. 54 in the Hoffman et al. 2018 GMD paper. Melt production in the channel is generally a small contribution to the total water balance, which may explain why the model matched GlaDS well for the SHMIP experiments. It's possible this correction will help with channel blowup events, or it could make them worse - it's hard to think through how this affects those events without better characterizing what's causing them. In any case, this is a clear omission and should be used going forward. --- .../src/Registry_subglacial_hydro.xml | 2 ++ .../mode_forward/mpas_li_subglacial_hydro.F | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 754e8385255..c9087d164de 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -251,6 +251,8 @@ description="divergence due to channel flow in subglacial hydrology system" /> + diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index ad3642622e1..054b756c1e0 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -259,6 +259,7 @@ subroutine li_SGH_solve(domain, err) real (kind=RKIND), dimension(:), pointer :: waterThicknessTendency real (kind=RKIND), dimension(:), pointer :: divergenceChannel real (kind=RKIND), dimension(:), pointer :: channelAreaChangeCell + real (kind=RKIND), dimension(:), pointer :: channelMeltInputCell real (kind=RKIND), dimension(:), pointer :: dvEdge real (kind=RKIND), dimension(:), pointer :: areaCell real (kind=RKIND), dimension(:), pointer :: waterVelocity @@ -534,6 +535,7 @@ subroutine li_SGH_solve(domain, err) call mpas_timer_start("halo updates") call mpas_dmpar_field_halo_exch(domain, 'divergenceChannel') call mpas_dmpar_field_halo_exch(domain, 'channelAreaChangeCell') + call mpas_dmpar_field_halo_exch(domain, 'channelMeltInputCell') call mpas_dmpar_field_halo_exch(domain, 'channelArea') call mpas_timer_stop("halo updates") endif @@ -570,12 +572,16 @@ subroutine li_SGH_solve(domain, err) call mpas_pool_get_array(hydroPool, 'divergence', divergence) call mpas_pool_get_array(hydroPool, 'divergenceChannel', divergenceChannel) call mpas_pool_get_array(hydroPool, 'channelAreaChangeCell', channelAreaChangeCell) + call mpas_pool_get_array(hydroPool, 'channelMeltInputCell', channelMeltInputCell) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) waterThicknessOld = waterThickness - waterThickness = waterThicknessOld + deltatSGH * ( (basalMeltInput + externalWaterInput) / rho_water - divergence & + waterThickness = waterThicknessOld + deltatSGH * ( & + (basalMeltInput + externalWaterInput) / rho_water & + + channelMeltInputCell & + - divergence & - divergenceChannel - channelAreaChangeCell & - - (Wtill - WtillOld) / deltatSGH) + - (Wtill - WtillOld) / deltatSGH ) waterThickness = waterThickness * li_mask_is_grounded_ice_int(cellMask) ! zero in non-grounded locations waterThickness = max(0.0_RKIND, waterThickness) divergence = divergence * li_mask_is_grounded_ice_int(cellMask) ! zero in non-grounded locations for more convenient viz @@ -1777,6 +1783,7 @@ subroutine update_channel(block, err) end where channelChangeRate = channelOpeningRate - channelClosingRate + !-------------------------------------------------------------------- end subroutine update_channel @@ -1816,9 +1823,11 @@ subroutine evolve_channel(block, err) type (mpas_pool_type), pointer :: meshPool real (kind=RKIND), dimension(:), pointer :: channelArea real (kind=RKIND), dimension(:), pointer :: channelDischarge + real (kind=RKIND), dimension(:), pointer :: channelMelt, channelPressureFreeze real (kind=RKIND), dimension(:), pointer :: channelChangeRate real (kind=RKIND), dimension(:), pointer :: divergenceChannel real (kind=RKIND), dimension(:), pointer :: channelAreaChangeCell + real (kind=RKIND), dimension(:), pointer :: channelMeltInputCell real (kind=RKIND), pointer :: deltatSGH integer, dimension(:), pointer :: nEdgesOnCell integer, dimension(:,:), pointer :: edgesOnCell @@ -1834,9 +1843,12 @@ subroutine evolve_channel(block, err) call mpas_pool_get_array(hydroPool, 'deltatSGH', deltatSGH) call mpas_pool_get_array(hydroPool, 'channelArea', channelArea) call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) + call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) + call mpas_pool_get_array(hydroPool, 'channelPressureFreeze', channelPressureFreeze) call mpas_pool_get_array(hydroPool, 'channelChangeRate', channelChangeRate) call mpas_pool_get_array(hydroPool, 'divergenceChannel', divergenceChannel) call mpas_pool_get_array(hydroPool, 'channelAreaChangeCell', channelAreaChangeCell) + call mpas_pool_get_array(hydroPool, 'channelMeltInputCell', channelMeltInputCell) call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) @@ -1848,6 +1860,7 @@ subroutine evolve_channel(block, err) ! Calculate flux divergence on cells and channel area change on cells divergenceChannel(:) = 0.0_RKIND ! zero div before accumulating channelAreaChangeCell(:) = 0.0_RKIND ! zero before accumulating + channelMeltInputCell(:) = 0.0_RKIND ! zero before accumulating ! loop over locally owned cells do iCell = 1, nCellsSolve ! TODO: could limit to grounded cells only @@ -1858,10 +1871,12 @@ subroutine evolve_channel(block, err) divergenceChannel(iCell) = divergenceChannel(iCell) - channelDischarge(iEdge) * edgeSignOnCell(iEdgeOnCell, iCell) channelAreaChangeCell(iCell) = channelChangeRate(iEdge) * dcEdge(iEdge) * 0.5_RKIND ! < only half of channel is in this cell + channelMeltInputCell(iCell) = 0.5_RKIND * (channelMelt(iEdge) - channelPressureFreeze(iEdge)) * dcEdge(iEdge) / rho_water end do ! edges end do ! cells divergenceChannel(1:nCellsSolve) = divergenceChannel(1:nCellsSolve) / areaCell(1:nCellsSolve) channelAreaChangeCell(1:nCellsSolve) = channelAreaChangeCell(1:nCellsSolve) / areaCell(1:nCellsSolve) + channelMeltInputCell(1:nCellsSolve) = channelMeltInputCell(1:nCellsSolve) / areaCell(1:nCellsSolve) ! Now update channel area channelArea = channelChangeRate * deltatSGH + channelArea From 9e29133edcf20018ce30414b354b812ee28b8098 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 17 May 2023 11:30:03 -0600 Subject: [PATCH 013/388] Revert "Ignore the water thickness head in the channel model" This reverts commit ae981817616596be19c52fad5a9089161d9c8d63. It seems like we would want the channel model to see the elevation head produced by a lake's water thickness to ensure that channel flow is consistent with the presence of the lake. This commit reverts the commit that dropped the water thickness elevation head from the hydropotential gradients used by the channel. In the sheet model, the elevation head is removed from the advection equation, but it is handled by the diffusion equation, so it's still represented in the evolution. As the channel model currently exists, the elevation head is almost completely absent (other than its effect on the magnitude of gradMagPhiEdge). It seems like this could lead to channels draining *into* lakes even when the full hydropotential gradient of the lake indicates water flow should be draining the lake. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 054b756c1e0..5d048074bea 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1652,7 +1652,7 @@ subroutine update_channel(block, err) real (kind=RKIND), dimension(:), pointer :: channelVelocity real (kind=RKIND), dimension(:), pointer :: gradMagPhiEdge real (kind=RKIND), dimension(:), pointer :: waterFlux - real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseSlopeNormal + real (kind=RKIND), dimension(:), pointer :: hydropotentialSlopeNormal real (kind=RKIND), dimension(:), pointer :: waterPressureSlopeNormal real (kind=RKIND), dimension(:), pointer :: channelOpeningRate real (kind=RKIND), dimension(:), pointer :: channelClosingRate @@ -1698,7 +1698,7 @@ subroutine update_channel(block, err) call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) call mpas_pool_get_array(hydroPool, 'channelVelocity', channelVelocity) call mpas_pool_get_array(hydroPool, 'gradMagPhiEdge', gradMagPhiEdge) - call mpas_pool_get_array(hydroPool, 'hydropotentialBaseSlopeNormal', hydropotentialBaseSlopeNormal) + call mpas_pool_get_array(hydroPool, 'hydropotentialSlopeNormal', hydropotentialSlopeNormal) call mpas_pool_get_array(hydroPool, 'waterPressureSlopeNormal', waterPressureSlopeNormal) call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) call mpas_pool_get_array(hydroPool, 'channelOpeningRate', channelOpeningRate) @@ -1720,7 +1720,7 @@ subroutine update_channel(block, err) channelDischarge(:) = 0.0_RKIND elsewhere channelDischarge = -1.0_RKIND * Kc * channelArea**alpha_c * gradMagPhiEdge**(beta_c - 2.0_RKIND) * & - hydropotentialBaseSlopeNormal + hydropotentialSlopeNormal end where where (waterFluxMask == 2) @@ -1752,8 +1752,8 @@ subroutine update_channel(block, err) Kc * channelArea**(alpha_c - 1.0_RKIND) * gradMagPhiEdge**(beta_c - 2.0_RKIND)) end where - channelMelt = (abs(channelDischarge * hydropotentialBaseSlopeNormal) & ! channel dissipation - + abs(waterFlux * hydropotentialBaseSlopeNormal * config_SGH_incipient_channel_width) & !some sheet dissipation + channelMelt = (abs(channelDischarge * hydropotentialSlopeNormal) & ! channel dissipation + + abs(waterFlux * hydropotentialSlopeNormal * config_SGH_incipient_channel_width) & !some sheet dissipation ) / latent_heat_ice channelPressureFreeze = -1.0_RKIND * iceMeltingPointPressureDependence * cp_freshwater * rho_water * & (channelDischarge + waterFlux * config_SGH_incipient_channel_width) & From d10446452ebb2fe4dfb48b9d1e245c9dce565639 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Thu, 18 May 2023 14:12:10 -0600 Subject: [PATCH 014/388] Disable diffusive water flux at grounding line The water thickness in the ocean is undefined, and if anything we'd have diffusion from the ocean (thick water layer) to the grounded ice, and we don't want any flux from the ocean inward. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 5d048074bea..d7b7d3deede 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -963,11 +963,15 @@ subroutine calc_edge_quantities(block, err) waterFluxAdvec(iEdge) = waterVelocity(iEdge) * waterThicknessEdgeUpwind(iEdge) ! diffusive flux - ! Note: At the GL, the water thickness for one cell will be 0, meaning a large gradient. However, the - ! diffusivity uses a one sided water thickness. It's unclear what really happens to lakes at the GL/margin. - waterFluxDiffu(iEdge) = -1.0_RKIND * diffusivity(iEdge) * (waterThickness(cell2) - waterThickness(cell1)) & + ! Note: Water thickness at the GL is undefined. I don't think we want to assume it's 0, and + ! we also don't want to assume it's the ocean water column height, because that would imply + ! a diffusive flux inward, which is undesirable. So disabling diffusion at the GL. + if (hydroMarineMarginMask(iEdge) == 1) then + waterFluxDiffu(iEdge) = 0.0_RKIND + else + waterFluxDiffu(iEdge) = -1.0_RKIND * diffusivity(iEdge) * (waterThickness(cell2) - waterThickness(cell1)) & / dcEdge(iEdge) - !endif + endif end do where (waterFluxMask == 2) waterFluxAdvec = 0.0_RKIND From 89b3ca1157e0058c357961164082228b92313765 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 19 May 2023 16:43:25 -0600 Subject: [PATCH 015/388] Move call to mpas_calculate_barycentric_weights_for_points Previously the call to mpas_calculate_barycentric_weights_for_points to set up barycentric weights for interpolation from cells to vertices occurred in the mpas_li_sia.F module. However, these weights may also be needed by the subglacial hydro code, which can be called with any (or none) velocity solver. This commit moves that initialization to mpas_li_setup and adds logic to call the weight generation routine if either the SIA or SGH code requires it. --- .../mpas-albany-landice/src/Registry.xml | 4 +- .../src/mode_forward/mpas_li_core.F | 4 + .../src/mode_forward/mpas_li_sia.F | 44 -------- .../src/shared/mpas_li_setup.F | 106 +++++++++++++++++- 4 files changed, 111 insertions(+), 47 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index 279d7fb3c0a..1a8523d3913 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -1125,10 +1125,10 @@ is the value of that variable from the *previous* time level! /> 0) then - call mpas_log_write("The 'from_vertex_barycentric' option for 'config_sia_tangent_slope_calculation' " & - // "does NOT work across the periodicity in periodic meshes. However, it does work within the interior " & - // "of the mesh.", MPAS_LOG_WARN) - endif - call mpas_deallocate_scratch_field(vertexIndicesField, .true.) - endif ! === error check if (err > 0) then diff --git a/components/mpas-albany-landice/src/shared/mpas_li_setup.F b/components/mpas-albany-landice/src/shared/mpas_li_setup.F index e231b4733bb..a77178001e3 100644 --- a/components/mpas-albany-landice/src/shared/mpas_li_setup.F +++ b/components/mpas-albany-landice/src/shared/mpas_li_setup.F @@ -53,7 +53,8 @@ module li_setup li_interpolate_vertex_to_cell_2d, & li_cells_to_vertices_1dfield_using_kiteAreas, & li_calculate_layerThickness, & - li_compute_gradient_2d + li_compute_gradient_2d, & + li_init_barycentric_weights_vertex !-------------------------------------------------------------------- @@ -817,6 +818,109 @@ subroutine li_compute_gradient_2d(& end subroutine li_compute_gradient_2d +!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +! +! routine li_init_barycentric_weights_vertex +! +!> \brief compute barycentric weights for interpolating cells to vertices +!> \author Matt Hoffman +!> \date May 2023 +!> \details +!> This routine uses a framework routine to compute the barycentric +!> weights for interpolating from cells to vertices +! +!----------------------------------------------------------------------- + + subroutine li_init_barycentric_weights_vertex(block, err) + + use mpas_geometry_utils, only: mpas_calculate_barycentric_weights_for_points + + !----------------------------------------------------------------- + ! input variables + !----------------------------------------------------------------- + + !----------------------------------------------------------------- + ! input/output variables + !----------------------------------------------------------------- + type (block_type), intent(inout) :: & + block !< Input/Output: block object + + !----------------------------------------------------------------- + ! output variables + !----------------------------------------------------------------- + integer, intent(out) :: err !< Output: error flag + + !----------------------------------------------------------------- + ! local variables + !----------------------------------------------------------------- + type (mpas_pool_type), pointer :: meshPool + type (mpas_pool_type), pointer :: scratchPool + integer :: iCell, iLevel, i, iVertex, err_tmp + integer, pointer :: nVertices + character (len=StrKIND), pointer :: config_velocity_solver + character (len=StrKIND), pointer :: config_sia_tangent_slope_calculation + logical, pointer :: config_SGH + character (len=StrKIND), pointer :: config_SGH_tangent_slope_calculation + integer, dimension(:,:), pointer :: baryCellsOnVertex + real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex + real (kind=RKIND), dimension(:), pointer :: xVertex, yVertex, zVertex + type (field1dInteger), pointer :: vertexIndicesField + + ! No block init needed. + err = 0 + err_tmp = 0 + + call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(block % structs, 'scratch', scratchPool) + call mpas_pool_get_array(meshPool, 'baryCellsOnVertex', baryCellsOnVertex) + call mpas_pool_get_array(meshPool, 'baryWeightsOnVertex', baryWeightsOnVertex) + call mpas_pool_get_array(meshPool, 'xVertex', xVertex) + call mpas_pool_get_array(meshPool, 'yVertex', yVertex) + call mpas_pool_get_array(meshPool, 'zVertex', zVertex) + call mpas_pool_get_config(liConfigs, 'config_velocity_solver', config_velocity_solver) + call mpas_pool_get_config(liConfigs, 'config_sia_tangent_slope_calculation', config_sia_tangent_slope_calculation) + call mpas_pool_get_config(liConfigs, 'config_SGH', config_SGH) + call mpas_pool_get_config(liConfigs, 'config_SGH_tangent_slope_calculation', config_SGH_tangent_slope_calculation) + call mpas_pool_get_field(scratchPool, 'vertexIndices', vertexIndicesField) + call mpas_pool_get_dimension(meshPool, 'nVertices', nVertices) + + if ( & + (trim(config_velocity_solver) == 'sia' .and. & + trim(config_sia_tangent_slope_calculation) == 'from_vertex_barycentric') & + .or. & + (config_SGH .and. trim(config_SGH_tangent_slope_calculation) == 'from_vertex_barycentric')) then + + call mpas_allocate_scratch_field(vertexIndicesField, .true.) + do iVertex = 1, nVertices + vertexIndicesField % array(iVertex) = iVertex + enddo + call mpas_calculate_barycentric_weights_for_points(meshPool, & + xVertex(1:nVertices), yVertex(1:nVertices), zVertex(1:nVertices), & + vertexIndicesField % array(1:nVertices), & + baryCellsOnVertex(:, 1:nVertices), baryWeightsOnVertex(:, 1:nVertices), err_tmp) + ! TODO: Until framework can handle periodic meshs gracefully, this will return an error + ! for periodic meshes. This error means that the velocity solver will be very wrong across + ! the periodicity, but it will be fine everywhere else. For now, just print a warning but + ! don't make this a fatal error. + !err = ior(err, err_tmp) + if (err_tmp > 0) then + call mpas_log_write("The 'from_vertex_barycentric' option for 'config_sia_tangent_slope_calculation' " & + // "'config_SGH_tangent_slope_calculation' " & + // "does NOT work across the periodicity in periodic meshes. However, it does work within the interior " & + // "of the mesh.", MPAS_LOG_WARN) + endif + call mpas_deallocate_scratch_field(vertexIndicesField, .true.) + + endif + + ! === error check + if (err > 0) then + call mpas_log_write("An error has occurred in li_init_barycentric_weights_vertex", MPAS_LOG_ERR) + endif + + end subroutine li_init_barycentric_weights_vertex + + !*********************************************************************** !*********************************************************************** ! Private subroutines: From 34279d01f978bd0e6639b02baf1dfdade018980f Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 19 May 2023 13:07:03 -0600 Subject: [PATCH 016/388] Zero gradients at edges of the mesh Without explicitly doing this, the gradients are likely using neighboring values of 0, which would yield unexpectedly large gradients. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index d7b7d3deede..82b4782b3e5 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -889,6 +889,16 @@ subroutine calc_edge_quantities(block, err) endif ! GL edge or grounded margin end do + ! zero gradients at boundaries of the mesh + do iEdge = 1, nEdges + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + if ((cell1 == nCells+1) .or. (cell2 == nCells+1)) then + hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND + hydropotentialSlopeNormal(iEdge) = 0.0_RKIND + waterPressureSlopeNormal(iEdge) = 0.0_RKIND + endif + end do ! Calculate tangent slope of hydropotentialBase - three possible methods to consider From be959a9c6daddf198fed032a920f53c261dd9919 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 19 May 2023 13:29:33 -0600 Subject: [PATCH 017/388] Treat tangent slope calculation near boundary of mesh This commit explicitly treats the calculation of hydropotentialBaseSlopeTangent near mesh boundaries. For the two vertex based methods, edges with vertices on the boundary of the mesh will have invalid values. For the normal slope method, any edges on cells that are at the edge of the mesh will have contaminated values. In those cases, set tangent slope to zero rather than leaving the possibility of garbage values. --- .../mode_forward/mpas_li_subglacial_hydro.F | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 82b4782b3e5..35974d867e2 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -744,6 +744,7 @@ subroutine calc_edge_quantities(block, err) integer, dimension(:), pointer :: edgeMask integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:,:), pointer :: verticesOnEdge + integer, dimension(:,:), pointer :: cellsOnVertex integer, dimension(:,:), pointer :: baryCellsOnVertex real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex real (kind=RKIND), pointer :: alpha, beta @@ -758,6 +759,7 @@ subroutine calc_edge_quantities(block, err) integer, pointer :: nCells integer, pointer :: nVertices integer :: iEdge, cell1, cell2 + integer :: i, j, iVertex, iCell real (kind=RKIND) :: velSign integer :: numGroundedCells integer :: err_tmp @@ -917,11 +919,14 @@ subroutine calc_edge_quantities(block, err) end select ! Now perform tangent slope calculation based on method chosen + ! For the two vertex based methods, edges with vertices on the boundary of the mesh will have invalid values + ! For the normal slope method, any edges on cells that are at the edge of the mesh will have + ! contaminated values. + call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) + call mpas_pool_get_array(meshPool, 'verticesOnEdge', verticesOnEdge) + call mpas_pool_get_array(meshPool, 'cellsOnVertex', cellsOnVertex) select case (trim(config_SGH_tangent_slope_calculation)) case ('from_vertex_barycentric', 'from_vertex_barycentric_kiteareas') - call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) - call mpas_pool_get_array(meshPool, 'verticesOnEdge', verticesOnEdge) do iEdge = 1, nEdges ! Only calculate slope for edges that have ice on at least one side. if ( li_mask_is_ice(edgeMask(iEdge)) ) then @@ -930,10 +935,26 @@ subroutine calc_edge_quantities(block, err) else hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND endif + ! check for edges where a vertex is on the edge of the mesh and zero the tangent slope there + do i = 1, 2 + iVertex = verticesOnEdge(i, iEdge) + do j = 1, 3 + iCell = cellsOnVertex(j, iVertex) + if (iCell == nCells + 1) then + hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND + endif + enddo + enddo end do ! edges case ('from_normal_slope') call mpas_tangential_vector_1d(hydropotentialBaseSlopeNormal, meshPool, & includeHalo=.false., tangentialVector=hydropotentialBaseSlopeTangent) + ! ensure that edges that don't have ice on at least one side have tangent slope set to zero + do iEdge = 1, nEdges + if ( .not. li_mask_is_ice(edgeMask(iEdge)) ) then + hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND + endif + end do ! edges case default call mpas_log_write('Invalid value for config_SGH_tangent_slope_calculation.', MPAS_LOG_ERR) err = 1 From e78b763bf00499204cf71a2f18207183c9112f22 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Mon, 22 May 2023 19:22:17 -0600 Subject: [PATCH 018/388] Adjust hydro CFL calculation to ignore invalid edges Without this change, the CFL condition might be overly restrictive because values from cells that aren't part of advection get included in the calculation and they may happen to have values that are more restrictive than the valid edges. --- .../mode_forward/mpas_li_subglacial_hydro.F | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 35974d867e2..cf02e943785 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -998,6 +998,7 @@ subroutine calc_edge_quantities(block, err) ! we also don't want to assume it's the ocean water column height, because that would imply ! a diffusive flux inward, which is undesirable. So disabling diffusion at the GL. if (hydroMarineMarginMask(iEdge) == 1) then + diffusivity(iEdge) = 0.0_RKIND waterFluxDiffu(iEdge) = 0.0_RKIND else waterFluxDiffu(iEdge) = -1.0_RKIND * diffusivity(iEdge) * (waterThickness(cell2) - waterThickness(cell1)) & @@ -1139,31 +1140,43 @@ subroutine check_timestep(domain, timeLeft, numSubCycles, err) call mpas_pool_get_array(meshPool, 'dcEdge', dcEdge) call mpas_pool_get_array(meshPool, 'indexToEdgeID', indexToEdgeID) - ! Calculate advective CFL-limited time step - dtSGHadvecBlock = 0.5_RKIND * minval(dcEdge(1:nEdgesSolve) / (abs(waterVelocity(1:nEdgesSolve)) & - + 1.0e-12_RKIND)) ! regularize - dtSGHadvecProc = min(dtSGHadvecProc, dtSGHadvecBlock) + dtSGHadvecBlock = bigNumber + dtSGHdiffuBlock = bigNumber + dtSGHpressureBlock = bigNumber + dtSGHadvecChanBlock = bigNumber + dtSGHdiffuChanBlock = bigNumber - ! Calculate diffusive CFL-limited time step - dtSGHdiffuBlock = 0.25_RKIND * minval(dcEdge(1:nEdgesSolve)**2 / (diffusivity(1:nEdgesSolve) + 1.0e-12_RKIND)) - dtSGHdiffuProc = min(dtSGHdiffuProc, dtSGHdiffuBlock) + do iEdge = 1, nEdgesSolve + ! Calculate advective CFL-limited time step + if (abs(waterVelocity(iEdge)) > 0.0) then + dtSGHadvecBlock = min(dtSGHadvecBlock, 0.5_RKIND * dcEdge(iEdge) / abs(waterVelocity(iEdge))) + endif - ! Calculate pressure limited time step - dtSGHpressureBlock = 1.0_RKIND * minval(porosity * dcEdge(1:nEdgesSolve)**2 & - / (2.0_RKIND * diffusivity(1:nEdgesSolve) + 1.0e-12_RKIND)) - dtSGHpressureProc = min(dtSGHpressureProc, dtSGHpressureBlock) + if (diffusivity(iEdge) > 0.0) then + ! Calculate diffusive CFL-limited time step + dtSGHdiffuBlock = min(dtSGHdiffuBlock, 0.25_RKIND * dcEdge(iEdge)**2 / diffusivity(iEdge)) + ! Calculate pressure limited time step + dtSGHpressureBlock = min(dtSGHpressureBlock, 1.0_RKIND * porosity * dcEdge(iEdge)**2 & + / (2.0_RKIND * diffusivity(iEdge))) + endif - if (config_SGH_chnl_active) then - ! Calculate channel advection limited time step - dtSGHadvecChanBlock = 0.5_RKIND * minval(dcEdge(1:nEdgesSolve) / (abs(channelVelocity(1:nEdgesSolve)) & - + 1.0e-12_RKIND)) - ! regularize - dtSGHadvecChanProc = min(dtSGHadvecChanProc, dtSGHadvecChanBlock) - ! Calculate channel diffusion limited time step - dtSGHdiffuChanBlock = 0.25_RKIND * minval(dcEdge(1:nEdgesSolve)**2 / (channelDiffusivity(1:nEdgesSolve) + & - 1.0e-12_RKIND)) - dtSGHdiffuChanProc = min(dtSGHdiffuChanProc, dtSGHdiffuChanBlock) - endif + if (config_SGH_chnl_active) then + if (abs(channelVelocity(iEdge)) > 0.0) then + ! Calculate channel advection limited time step + dtSGHadvecChanBlock = min(dtSGHadvecChanBlock, 0.5_RKIND * dcEdge(iEdge) / (abs(channelVelocity(iEdge)))) + endif + ! Calculate channel diffusion limited time step + if (channelDiffusivity(iEdge) > 0.0) then + dtSGHdiffuChanBlock = min(dtSGHdiffuChanBlock, 0.25_RKIND * dcEdge(iEdge)**2 / channelDiffusivity(iEdge)) + endif + endif + enddo + + dtSGHadvecProc = min(dtSGHadvecProc, dtSGHadvecBlock) + dtSGHdiffuProc = min(dtSGHdiffuProc, dtSGHdiffuBlock) + dtSGHpressureProc = min(dtSGHpressureProc, dtSGHpressureBlock) + dtSGHadvecChanProc = min(dtSGHadvecChanProc, dtSGHadvecChanBlock) + dtSGHdiffuChanProc = min(dtSGHdiffuChanProc, dtSGHdiffuChanBlock) ! Master deltat is needed below, so grab it in this block loop call mpas_pool_get_array(meshPool, 'deltat', deltat) From 4f448669204b5a947760807f6fbd8184d6b96bac Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Thu, 25 May 2023 14:21:24 -0600 Subject: [PATCH 019/388] Update gradient calulations at boundaries of hydro domain Simplify calculation disallowing inflow and move it *before* extra logic limiting outflow gradient. --- .../mode_forward/mpas_li_subglacial_hydro.F | 50 +++++++------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index cf02e943785..aeb9da614a0 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -833,12 +833,29 @@ subroutine calc_edge_quantities(block, err) waterPressureSlopeNormal(iEdge) = (waterPressure(cell2) - waterPressure(cell1)) / dcEdge(iEdge) end do + ! At boundaries of hydro domain, disallow inflow. Allow outflow if hydropotential gradient requires it. + do iEdge = 1, nEdges + if ( (li_mask_is_margin(edgeMask(iEdge)) .and. li_mask_is_grounded_ice(edgeMask(iEdge))) .or. & + (hydroMarineMarginMask(iEdge)==1)) then + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + if (li_mask_is_grounded_ice(cellMask(cell1))) then ! cell2 is the cell outside the hydro domain + hydropotentialBaseSlopeNormal(iEdge) = min(0.0_RKIND, hydropotentialBaseSlopeNormal(iEdge)) + hydropotentialSlopeNormal(iEdge) = min(0.0_RKIND, hydropotentialSlopeNormal(iEdge)) + else ! cell1 is the cell outside the hydro domain + hydropotentialBaseSlopeNormal(iEdge) = max(0.0_RKIND, hydropotentialBaseSlopeNormal(iEdge)) + hydropotentialSlopeNormal(iEdge) = max(0.0_RKIND, hydropotentialSlopeNormal(iEdge)) + endif ! which cell is icefree + endif ! if edge of grounded ice + end do + ! At terrestrial margin, ignore the downslope bed topography gradient. Including it can lead to unrealistically large ! hydropotential gradients and unstable channel growth. ! We also want to do this at marine margins because otherwise the offshore topography can create a barrier to flow, ! but that is unrealistic. - ! So for all boundaries of the hydro system, the hydropotential at the margin should be determined by the geometry - ! at the edge of the cell in a 1-sided sense + ! So for all boundaries of the hydro system where outflow is occuring, + ! the hydropotential at the margin should be determined by the geometry + ! at the edge of the cell in a 1-sided sense. do iEdge = 1, nEdges if ( (li_mask_is_margin(edgeMask(iEdge)) .and. li_mask_is_grounded_ice(edgeMask(iEdge))) .or. & (hydroMarineMarginMask(iEdge)==1)) then @@ -862,35 +879,6 @@ subroutine calc_edge_quantities(block, err) endif ! if edge of grounded ice end do - ! Disallow flow from ocean to glacier, or land to glacier, - ! which can occur under some circumstances - ! For ocean this is invalid because ocean water has a different density! - ! For land this would only happen if there is a supply of water, which is not currently handled. - ! Do this by simply zeroing the hydropotential gradient in those cases. - ! (Do this step only after the other hydropotential special cases are treated above.) - do iEdge = 1, nEdges - ! Find edges along GL or margin to check for 'backwards' flow - if ((hydroMarineMarginMask(iEdge)==1) .or. & - li_mask_is_margin(edgeMask(iEdge)) ) then - ! Now check if flow is backwards - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) - if (hydropotentialBaseSlopeNormal(iEdge) > 0.0_RKIND) then - ! flow is from cell2 to cell1 - if (.not. li_mask_is_grounded_ice(cellMask(cell2))) then - hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND - hydropotentialSlopeNormal(iEdge) = 0.0_RKIND - endif - elseif (hydropotentialBaseSlopeNormal(iEdge) < 0.0_RKIND) then - ! flow is from cell1 to cell2 - if (.not. li_mask_is_grounded_ice(cellMask(cell1))) then - hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND - hydropotentialSlopeNormal(iEdge) = 0.0_RKIND - endif - endif - endif ! GL edge or grounded margin - end do - ! zero gradients at boundaries of the mesh do iEdge = 1, nEdges cell1 = cellsOnEdge(1, iEdge) From f82cddd6e3f6dd43cb03877cf4897532c3087db7 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Thu, 25 May 2023 17:33:37 -0600 Subject: [PATCH 020/388] Channel gradMagPhiEdge dependent on full water hydropotential Channels now use updated version of gradMagPhiEdge, which is dependent on full hydropotential. This is done to keep channels from filling up lakes even when lake is full and hydropotential is in opposite direction. Distributed system is now dependent on new variable gradMagPhiBaseEdge, which is dependent only on hydropotentialBase and is equivalent to gradMagPhiEdge in previous commits. --- .../src/Registry_subglacial_hydro.xml | 8 ++++- .../mode_forward/mpas_li_subglacial_hydro.F | 36 +++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index c9087d164de..602b7c11f6d 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -196,14 +196,20 @@ description="hydropotential in subglacial hydrology system without water thickness contribution" /> + - + + 0.0_RKIND) then ! Use a thickness weighted conductivity coeff. when water thickness exceeds bump height @@ -959,12 +983,12 @@ subroutine calc_edge_quantities(block, err) conduc_coeff_drowned * max(waterThicknessEdge(iEdge) - bedRoughMax, 0.0_RKIND)) / & (waterThicknessEdge(iEdge) + 1.0e-16_RKIND) ! Regularization only applies where value doesn't matter effectiveConducEdge(iEdge) = conduc_coeff_wtd * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) * & - (gradMagPhiEdge(iEdge)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization + (gradMagPhiBaseEdge(iEdge)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization end do else ! Just use a single conductivity coeff. effectiveConducEdge(:) = conduc_coeff * waterThicknessEdge(:)**(alpha-1.0_RKIND) *& - (gradMagPhiEdge(:)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization + (gradMagPhiBaseEdge(:)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization endif ! calculate diffusivity on edges From dc6b48e5f2659b478278957f8bc952c771f6cf88 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 12 Jun 2023 11:01:31 -0600 Subject: [PATCH 021/388] Create hydroTerrestrialMarginMask Creates hydroTerrestrialMarginMask variable, which designates the terrestrial margins of the active subglacial hydrology model --- .../src/Registry_subglacial_hydro.xml | 4 +++- .../src/mode_forward/mpas_li_subglacial_hydro.F | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 602b7c11f6d..66a4a306bbf 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -174,7 +174,9 @@ description="mask indicating how to handle fluxes on each edge: 0=calculate based on hydropotential gradient; 1=allow outflow based on hydropotential gradient, but no inflow (NOT YET IMPLEMENTED); 2=zero flux" /> - + diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index f7118b3fe85..f73177ab390 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2183,6 +2183,7 @@ subroutine calc_hydro_mask(domain) type (mpas_pool_type), pointer :: meshPool real (kind=RKIND), dimension(:), pointer :: bedTopography integer, dimension(:), pointer :: hydroMarineMarginMask + integer, dimension(:), pointer :: hydroTerrestrialMarginMask integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:), pointer :: cellMask integer, pointer :: nEdgesSolve @@ -2199,6 +2200,7 @@ subroutine calc_hydro_mask(domain) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) + call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) @@ -2218,6 +2220,20 @@ subroutine calc_hydro_mask(domain) endif enddo + hydroTerrestrialMarginMask(:) = 0 + do iEdge = 1, nEdgesSolve + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + !Look for edges with 1 cell on grounding ice and the other cell on land without ice + if ((li_mask_is_grounded_ice(cellMask(cell1))) .and. ( .not. li_mask_is_ice(cellMask(cell2))) & + .and. (bedTopography(cell2) > config_sea_level)) then + hydroTerrestrialMarginMask(iEdge) = 1 + elseif ((li_mask_is_grounded_ice(cellMask(cell2))) .and. ( .not. li_mask_is_ice(cellMask(cell1))) & + .and. (bedTopography(cell1) > config_sea_level)) then + hydroTerrestrialMarginMask(iEdge) = 1 + endif + enddo + block => block % next end do From 69d566d521d125f2cded4c458797e8a874ba7634 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 20 Jun 2023 17:29:32 -0600 Subject: [PATCH 022/388] Edit SGH_tangent_slope_calculation description Edits description of config_SGH_tangent_slope_calculation in Registry_subglacial_hydro.xml based on detailed testing of 'from_normal_slope' and 'from_vertex_barycentric' options. --- .../mpas-albany-landice/src/Registry_subglacial_hydro.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 66a4a306bbf..b70e885eb59 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -24,7 +24,7 @@ description="Selection of the method for calculating the tangent component of slope at edges. 'from_vertex_barycentric' interpolates scalar values from cell centers to vertices using the barycentric interpolation routine in operators (mpas_cells_to_points_using_baryweights) and then calculates the slope between vertices. It works for obtuse triangles, but will not work correctly across the edges of periodic meshes. 'from_vertex_barycentric_kiteareas' interpolates scalar values from cell centers to vertices using barycentric interpolation based on kiterea values and then calculates the slope between vertices. It will work across the edges of periodic meshes, but will not work correctly for obtuse triangles. -'from_normal_slope' uses the vector operator mpas_tangential_vector_1d to calculate the tangent slopes from the normal slopes on the edges of the adjacent cells. It will work for any mesh configuration, but is the least accurate method." +'from_normal_slope' uses the vector operator mpas_tangential_vector_1d to calculate the tangent slopes from the normal slopes on the edges of the adjacent cells. It will work for any mesh configuration. 'from_normal_slope' uses a larger stencil, so may therefore produce a smoother 'gradMagPhiEdge' field. Detailed testing yielded nearly identical results between 'from_normal_slope' and 'from_vertex_barycentric' methods, but 'from_normal_slope' seemed to produce slightly more stable results at the grounding line." possible_values="'from_vertex_barycentric', 'from_vertex_barycentric_kiteareas', 'from_normal_slope'" /> Date: Wed, 19 Jul 2023 14:56:46 -0600 Subject: [PATCH 023/388] Zero diffusivity at boundary edges Explicitly sets diffusivity to zero at boundary edges, instead of just waterFluxDiff --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 1 + 1 file changed, 1 insertion(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index f73177ab390..5a4049f146e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1018,6 +1018,7 @@ subroutine calc_edge_quantities(block, err) endif end do where (waterFluxMask == 2) + diffusivity = 0.0_RKIND waterFluxAdvec = 0.0_RKIND waterFluxDiffu = 0.0_RKIND waterVelocity = 0.0_RKIND From 7529d5d5b2042c5212969bd94deca8f0ae6a614b Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 1 Dec 2023 12:40:09 -0800 Subject: [PATCH 024/388] hydroTerrestrialMarginMask >= sea level Redfines hydroTerrestiralMarineMargin to AT or above sea level, whereas hydroMarineMarginMask is exclusively below sea level. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 5a4049f146e..f02e9860e5e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2227,10 +2227,10 @@ subroutine calc_hydro_mask(domain) cell2 = cellsOnEdge(2, iEdge) !Look for edges with 1 cell on grounding ice and the other cell on land without ice if ((li_mask_is_grounded_ice(cellMask(cell1))) .and. ( .not. li_mask_is_ice(cellMask(cell2))) & - .and. (bedTopography(cell2) > config_sea_level)) then + .and. (bedTopography(cell2) >= config_sea_level)) then hydroTerrestrialMarginMask(iEdge) = 1 elseif ((li_mask_is_grounded_ice(cellMask(cell2))) .and. ( .not. li_mask_is_ice(cellMask(cell1))) & - .and. (bedTopography(cell1) > config_sea_level)) then + .and. (bedTopography(cell1) >= config_sea_level)) then hydroTerrestrialMarginMask(iEdge) = 1 endif enddo From 6fb6db5a6c8e29b1c6739538272f06e5115bfdde Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 5 Feb 2024 14:35:47 -0700 Subject: [PATCH 025/388] channelAreaChangeCell/channelMeltInputCell debug Debugs calculations of channelAreaChangeCell and channelMeltInputCell. Loop where these were being calculated was overwritting cell values each iteration through nEdgesOnCell. Now each cell is the sum of all of its edges as intended. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index f02e9860e5e..e823785f251 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1930,10 +1930,11 @@ subroutine evolve_channel(block, err) iEdge = edgesOnCell(iEdgeOnCell, iCell) ! add on advective & diffusive fluxes divergenceChannel(iCell) = divergenceChannel(iCell) - channelDischarge(iEdge) * edgeSignOnCell(iEdgeOnCell, iCell) - channelAreaChangeCell(iCell) = channelChangeRate(iEdge) * dcEdge(iEdge) * 0.5_RKIND + channelAreaChangeCell(iCell) = channelChangeRate(iEdge) * dcEdge(iEdge) * 0.5_RKIND + channelAreaChangeCell(iCell) ! < only half of channel is in this cell - channelMeltInputCell(iCell) = 0.5_RKIND * (channelMelt(iEdge) - channelPressureFreeze(iEdge)) * dcEdge(iEdge) / rho_water + channelMeltInputCell(iCell) = 0.5_RKIND * (channelMelt(iEdge) - channelPressureFreeze(iEdge)) * dcEdge(iEdge) / rho_water + channelMeltInputCell(iCell) end do ! edges + end do ! cells divergenceChannel(1:nCellsSolve) = divergenceChannel(1:nCellsSolve) / areaCell(1:nCellsSolve) channelAreaChangeCell(1:nCellsSolve) = channelAreaChangeCell(1:nCellsSolve) / areaCell(1:nCellsSolve) From 489805df75a1054db0f7ee3b3a0e6486b24f6973 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Tue, 13 Feb 2024 13:24:58 -0700 Subject: [PATCH 026/388] fix typo --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index e823785f251..bbabf2e10ec 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -900,7 +900,7 @@ subroutine calc_edge_quantities(block, err) ! Calculate hydropotentialBaseVertex if needed call mpas_pool_get_array(hydroPool, 'hydropotentialBaseVertex', hydropotentialBaseVertex) ! < this array could be protected by logic if desired - ! caluculate hydropotentialVertex if needed + ! calculate hydropotentialVertex if needed call mpas_pool_get_array(hydroPool, 'hydropotentialVertex', hydropotentialVertex) ! < this array could be protected by logic if desired select case (trim(config_SGH_tangent_slope_calculation)) From 58b91c193de583cf483b938744d1263e421452e7 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Tue, 13 Feb 2024 16:32:42 -0700 Subject: [PATCH 027/388] Add halo updates on two channel variables This is necessary to get BFB results on different decompositions. This addition was made necessary by c9c13aa5d4abb80e398ba361fb362ececb82b478. There may be a way to adjust halo updates to avoid needing to add these both, as they are both local calculations. But it is likely complex, so this solution is adequate in that it works. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index bbabf2e10ec..ba5a359301e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -465,6 +465,8 @@ subroutine li_SGH_solve(domain, err) call mpas_timer_start("halo updates") call mpas_dmpar_field_halo_exch(domain, 'channelChangeRate') call mpas_dmpar_field_halo_exch(domain, 'channelDischarge') + call mpas_dmpar_field_halo_exch(domain, 'channelMelt') + call mpas_dmpar_field_halo_exch(domain, 'channelPressureFreeze') call mpas_timer_stop("halo updates") endif From 4210a61acbdfd197bf00a48728cd575fb1e0dcda Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 15 Feb 2024 17:08:59 -0500 Subject: [PATCH 028/388] misc updates for the pam_debug routines --- .../eam/src/physics/crm/pam/pam_debug.h | 117 ++++++++++++------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_debug.h b/components/eam/src/physics/crm/pam/pam_debug.h index 5186d51c6a9..f4d8cdb1eda 100644 --- a/components/eam/src/physics/crm/pam/pam_debug.h +++ b/components/eam/src/physics/crm/pam/pam_debug.h @@ -16,29 +16,33 @@ inline void pam_debug_init( pam::PamCoupler &coupler ) { auto nens = coupler.get_option("ncrms"); //------------------------------------------------------------------------------------------------ dm_device.register_and_allocate("debug_save_temp", "saved temp for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); - dm_device.register_and_allocate("debug_save_rhod", "saved rhod for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhov", "saved rhov for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhoc", "saved rhoc for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhoi", "saved rhoi for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); + dm_device.register_and_allocate("debug_save_uvel", "saved uvel for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); + dm_device.register_and_allocate("debug_save_wvel", "saved wvel for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); auto debug_save_temp = dm_device.get("debug_save_temp"); - auto debug_save_rhod = dm_device.get("debug_save_rhod"); auto debug_save_rhov = dm_device.get("debug_save_rhov"); auto debug_save_rhoc = dm_device.get("debug_save_rhoc"); auto debug_save_rhoi = dm_device.get("debug_save_rhoi"); + auto debug_save_uvel = dm_device.get("debug_save_uvel"); + auto debug_save_wvel = dm_device.get("debug_save_wvel"); //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp"); - auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhoc = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice"); + auto uvel = dm_device.get("uvel"); + auto wvel = dm_device.get("wvel"); //------------------------------------------------------------------------------------------------ parallel_for("copy data to saved debug variables", SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); - debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); debug_save_rhov(k,j,i,iens) = rhov(k,j,i,iens); debug_save_rhoc(k,j,i,iens) = rhoc(k,j,i,iens); debug_save_rhoi(k,j,i,iens) = rhoi(k,j,i,iens); + debug_save_uvel(k,j,i,iens) = uvel(k,j,i,iens); + debug_save_wvel(k,j,i,iens) = wvel(k,j,i,iens); }); //------------------------------------------------------------------------------------------------ } @@ -48,81 +52,124 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; auto &dm_device = coupler.get_data_manager_device_readwrite(); - auto &dm_host = coupler.get_data_manager_host_readwrite(); + auto &dm_host = coupler.get_data_manager_host_readonly(); auto nx = coupler.get_option("crm_nx"); auto ny = coupler.get_option("crm_ny"); auto nz = coupler.get_option("crm_nz"); auto nens = coupler.get_option("ncrms"); - auto temp = dm_device.get("temp"); - auto rhod = dm_device.get("density_dry"); - auto rhov = dm_device.get("water_vapor"); - auto rhoc = dm_device.get("cloud_water"); - auto rhoi = dm_device.get("ice"); + auto temp = dm_device.get("temp"); + auto rhov = dm_device.get("water_vapor"); + auto rhoc = dm_device.get("cloud_water"); + auto rhoi = dm_device.get("ice"); + auto uvel = dm_device.get("uvel"); + auto wvel = dm_device.get("wvel"); auto debug_save_temp = dm_device.get("debug_save_temp"); - auto debug_save_rhod = dm_device.get("debug_save_rhod"); auto debug_save_rhov = dm_device.get("debug_save_rhov"); auto debug_save_rhoc = dm_device.get("debug_save_rhoc"); auto debug_save_rhoi = dm_device.get("debug_save_rhoi"); - real grav = 9.80616; - auto input_phis = dm_host.get("input_phis").createDeviceCopy(); + auto debug_save_uvel = dm_device.get("debug_save_uvel"); + auto debug_save_wvel = dm_device.get("debug_save_wvel"); auto lat = dm_host.get("latitude" ).createDeviceCopy(); auto lon = dm_host.get("longitude" ).createDeviceCopy(); + auto input_phis = dm_host.get("input_phis").createDeviceCopy(); + real grav = 9.80616; //------------------------------------------------------------------------------------------------ // Check for invalid values parallel_for("", SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { + auto phis = input_phis(iens)/grav; // Check for NaNs const auto is_nan_t_atm = isnan( temp(k,j,i,iens) ); - const auto is_nan_r_atm = isnan( rhod(k,j,i,iens) ); const auto is_nan_q_atm = isnan( rhov(k,j,i,iens) ); - if ( is_nan_t_atm || is_nan_r_atm || is_nan_q_atm ) { - auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g \n", + if ( is_nan_t_atm || is_nan_q_atm ) { + printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), - rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens) + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) ); } // Check for negative values const auto is_neg_t_atm = temp(k,j,i,iens)<0; - const auto is_neg_r_atm = rhod(k,j,i,iens)<0; const auto is_neg_q_atm = rhov(k,j,i,iens)<0; - if ( is_neg_t_atm || is_neg_r_atm || is_neg_q_atm ) { - auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g \n", + if ( is_neg_t_atm || is_neg_q_atm ) { + printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), - rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens) + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } + // Check for low temperature + const auto is_low_t = temp(k,j,i,iens)<100; + if ( is_low_t ) { + printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } + // Check for large vertical velocity + const auto is_large_pos_w = wvel(k,j,i,iens)> 40; + const auto is_large_neg_w = wvel(k,j,i,iens)<-40; + if ( is_large_pos_w || is_large_neg_w ) { + printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) ); } // update saved previous values debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); - debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); debug_save_rhov(k,j,i,iens) = rhov(k,j,i,iens); debug_save_rhoc(k,j,i,iens) = rhoc(k,j,i,iens); debug_save_rhoi(k,j,i,iens) = rhoi(k,j,i,iens); + debug_save_uvel(k,j,i,iens) = uvel(k,j,i,iens); + debug_save_wvel(k,j,i,iens) = wvel(k,j,i,iens); }); //------------------------------------------------------------------------------------------------ } // print the min and max of PAM state variables to help look for problems // void print_state_min_max( pam::PamCoupler &coupler, std::string id ) { - // auto &dm_device = coupler.get_data_manager_device_readwrite(); + // auto &dm_device = coupler.get_data_manager_device_readonly(); // auto nz = coupler.get_option("crm_nz"); // auto nx = coupler.get_option("crm_nx"); // auto ny = coupler.get_option("crm_ny"); @@ -184,18 +231,18 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { void pam_debug_print_state( pam::PamCoupler &coupler, int id ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; - auto &dm_device = coupler.get_data_manager_device_readwrite(); + auto &dm_device = coupler.get_data_manager_device_readonly(); auto nz = coupler.get_option("crm_nz"); auto nx = coupler.get_option("crm_nx"); auto ny = coupler.get_option("crm_ny"); auto nens = coupler.get_option("ncrms"); // auto pmid = coupler.compute_pressure_array(); // auto zmid = dm_device.get("vertical_midpoint_height" ); - auto temp = dm_device.get("temp"); - auto rho_v = dm_device.get("water_vapor"); - auto rho_c = dm_device.get("cloud_water"); - auto rho_d = dm_device.get("density_dry"); - auto rho_i = dm_device.get("ice"); + auto temp = dm_device.get("temp"); + auto rho_v = dm_device.get("water_vapor"); + auto rho_c = dm_device.get("cloud_water"); + auto rho_d = dm_device.get("density_dry"); + auto rho_i = dm_device.get("ice"); // parallel_for("", SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { parallel_for("pam_debug_print_state", SimpleBounds<2>(nz,nx), YAKL_LAMBDA (int k, int i) { int j = 0; From 0def774fe8d97cc5a890f48604062dcabea96635 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 15 Feb 2024 17:19:56 -0500 Subject: [PATCH 029/388] add MMF_PAM_dyn_per_phys namelist parameter --- components/eam/bld/build-namelist | 3 +++ .../eam/bld/namelist_files/namelist_defaults_eam.xml | 2 +- components/eam/bld/namelist_files/namelist_definition.xml | 6 ++++++ components/eam/src/physics/cam/phys_control.F90 | 8 ++++++-- components/eam/src/physics/crm/crm_physics.F90 | 7 +++++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/components/eam/bld/build-namelist b/components/eam/bld/build-namelist index 5a29d02bba4..c94bb5054d5 100755 --- a/components/eam/bld/build-namelist +++ b/components/eam/bld/build-namelist @@ -3885,6 +3885,9 @@ if ($cfg->get('use_MMF')) { # MMF CRM domain orientation add_default($nl, 'MMF_orientation_angle'); + + # PAM dynamics sub-stepping parameter + add_default($nl, 'MMF_PAM_dyn_per_phys'); } add_default($nl, 'do_aerocom_ind3'); diff --git a/components/eam/bld/namelist_files/namelist_defaults_eam.xml b/components/eam/bld/namelist_files/namelist_defaults_eam.xml index c5a61b500d2..4768f1799a4 100755 --- a/components/eam/bld/namelist_files/namelist_defaults_eam.xml +++ b/components/eam/bld/namelist_files/namelist_defaults_eam.xml @@ -879,7 +879,7 @@ 0 .false. .true. - + 2 90.0 0.0 diff --git a/components/eam/bld/namelist_files/namelist_definition.xml b/components/eam/bld/namelist_files/namelist_definition.xml index fb5049df211..dc63a488a6b 100644 --- a/components/eam/bld/namelist_files/namelist_definition.xml +++ b/components/eam/bld/namelist_files/namelist_definition.xml @@ -4769,6 +4769,12 @@ Defaults: 3D CRM: 0 + +Number of PAM dycor calls per physics time step. +Default: 2 + + Wavenumber cutoff for filtered MMF variance transport. diff --git a/components/eam/src/physics/cam/phys_control.F90 b/components/eam/src/physics/cam/phys_control.F90 index c4d4b7fba7f..41cd05e2714 100644 --- a/components/eam/src/physics/cam/phys_control.F90 +++ b/components/eam/src/physics/cam/phys_control.F90 @@ -72,6 +72,7 @@ module phys_control logical :: use_crm_accel = .false. ! true => use MMF CRM mean-state acceleration (MSA) real(r8) :: crm_accel_factor = 2.D0 ! CRM acceleration factor logical :: crm_accel_uv = .true. ! true => apply MMF CRM MSA to momentum fields +integer :: MMF_PAM_dyn_per_phys = 2 ! PAM CRM dynamics steps per CRM physics steps logical :: use_subcol_microp = .false. ! if .true. then use sub-columns in microphysics @@ -229,7 +230,7 @@ subroutine phys_ctl_readnl(nlfile) eddy_scheme, microp_scheme, macrop_scheme, radiation_scheme, srf_flux_avg, & MMF_microphysics_scheme, MMF_orientation_angle, use_MMF, use_ECPP, & use_MMF_VT, MMF_VT_wn_max, use_MMF_ESMT, & - use_crm_accel, crm_accel_factor, crm_accel_uv, & + use_crm_accel, crm_accel_factor, crm_accel_uv, MMF_PAM_dyn_per_phys, & use_subcol_microp, atm_dep_flux, history_amwg, history_verbose, history_vdiag, & get_presc_aero_data,history_aerosol, history_aero_optics, & is_output_interactive_volc, & @@ -314,6 +315,7 @@ subroutine phys_ctl_readnl(nlfile) call mpibcast(use_crm_accel, 1 , mpilog, 0, mpicom) call mpibcast(crm_accel_factor, 1 , mpir8, 0, mpicom) call mpibcast(crm_accel_uv, 1 , mpilog, 0, mpicom) + call mpibcast(MMF_PAM_dyn_per_phys, 1 , mpiint, 0, mpicom) call mpibcast(use_subcol_microp, 1 , mpilog, 0, mpicom) call mpibcast(atm_dep_flux, 1 , mpilog, 0, mpicom) call mpibcast(history_amwg, 1 , mpilog, 0, mpicom) @@ -598,7 +600,7 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & prog_modal_aero_out, macrop_scheme_out, ideal_phys_option_out, & use_MMF_out, use_ECPP_out, MMF_microphysics_scheme_out, & MMF_orientation_angle_out, use_MMF_VT_out, MMF_VT_wn_max_out, use_MMF_ESMT_out, & - use_crm_accel_out, crm_accel_factor_out, crm_accel_uv_out, & + use_crm_accel_out, crm_accel_factor_out, crm_accel_uv_out, MMF_PAM_dyn_per_phys_out, & do_clubb_sgs_out, do_shoc_sgs_out, do_tms_out, state_debug_checks_out, & linearize_pbl_winds_out, export_gustiness_out, & do_aerocom_ind3_out, & @@ -641,6 +643,7 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & logical, intent(out), optional :: use_crm_accel_out real(r8), intent(out), optional :: crm_accel_factor_out logical, intent(out), optional :: crm_accel_uv_out + integer, intent(out), optional :: MMF_PAM_dyn_per_phys_out logical, intent(out), optional :: use_subcol_microp_out logical, intent(out), optional :: atm_dep_flux_out logical, intent(out), optional :: history_amwg_out @@ -745,6 +748,7 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & if ( present(use_crm_accel_out ) ) use_crm_accel_out = use_crm_accel if ( present(crm_accel_factor_out ) ) crm_accel_factor_out = crm_accel_factor if ( present(crm_accel_uv_out ) ) crm_accel_uv_out = crm_accel_uv + if ( present(MMF_PAM_dyn_per_phys ) ) MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys if ( present(use_subcol_microp_out ) ) use_subcol_microp_out = use_subcol_microp if ( present(macrop_scheme_out ) ) macrop_scheme_out = macrop_scheme diff --git a/components/eam/src/physics/crm/crm_physics.F90 b/components/eam/src/physics/crm/crm_physics.F90 index 66e5b57e28e..31654e2bb7a 100644 --- a/components/eam/src/physics/crm/crm_physics.F90 +++ b/components/eam/src/physics/crm/crm_physics.F90 @@ -620,6 +620,8 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, logical :: use_MMF_VT_tmp ! flag for MMF variance transport (for Fortran CRM) logical :: use_MMF_ESMT_tmp ! flag for MMF scalar momentum transport (for Fortran CRM) integer :: MMF_VT_wn_max ! wavenumber cutoff for filtered variance transport + + integer :: MMF_PAM_dyn_per_phys ! PAM CRM dynamics steps per CRM physics steps real(r8) :: tmp_e_sat ! temporary saturation vapor pressure real(r8) :: tmp_q_sat ! temporary saturation specific humidity @@ -732,6 +734,9 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, use_crm_accel = use_crm_accel_tmp crm_accel_uv = crm_accel_uv_tmp + ! PAM namelist options + call phys_getopts(MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys) + nstep = get_nstep() itim = pbuf_old_tim_idx() ! "Old" pbuf time index (what does all this mean?) @@ -1459,6 +1464,8 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, call pam_set_option('enable_physics_tend_stats', .false. ) + call pam_set_option('crm_dyn_per_phys', MMF_PAM_dyn_per_phys ) + call pam_set_option('is_first_step', (nstep<=1) ) call pam_set_option('is_restart', (nsrest>0) ) call pam_set_option('am_i_root', masterproc ) From 9a25fc689c29fcbcf6725f09859fcb91c3c46a2d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 15 Feb 2024 17:58:22 -0500 Subject: [PATCH 030/388] pam driver updates --- .../eam/src/physics/crm/pam/pam_driver.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index f131bbd44f0..128974a856e 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -24,7 +24,7 @@ #include "p3_f90.hpp" #include "pam_debug.h" -bool constexpr enable_check_state = false; +bool constexpr enable_check_state = true; extern "C" void pam_driver() { //------------------------------------------------------------------------------------------------ @@ -50,12 +50,6 @@ extern "C" void pam_driver() { //------------------------------------------------------------------------------------------------ // set various coupler options coupler.set_option("gcm_physics_dt",gcm_dt); - #ifdef MMF_PAM_DPP - // this is leftover from debugging, but it might still be useful for testing values of crm_per_phys - coupler.set_option("crm_per_phys",MMF_PAM_DPP); - #else - coupler.set_option("crm_per_phys",2); // # of PAM-C dynamics steps per physics - #endif coupler.set_option("sponge_num_layers",crm_nz*0.3); // depth of sponge layer coupler.set_option("sponge_time_scale",60); // minimum damping timescale at top coupler.set_option("crm_acceleration_ceaseflag",false); @@ -143,6 +137,9 @@ extern "C" void pam_driver() { dycore.declare_current_profile_as_hydrostatic(coupler,/*use_gcm_data=*/true); #endif + #ifdef MMF_DISABLE_DENSITY_RECALL + do_density_save_recall = false; + #endif //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ @@ -168,8 +165,9 @@ extern "C" void pam_driver() { // run a PAM time step coupler.run_module( "apply_gcm_forcing_tendencies" , modules::apply_gcm_forcing_tendencies ); - coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); if (enable_check_state) { pam_debug_check_state(coupler, 2, nstep); } + coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); + if (enable_check_state) { pam_debug_check_state(coupler, 3, nstep); } // Dynamics if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } @@ -177,13 +175,13 @@ extern "C" void pam_driver() { coupler.run_module( "dycore", [&] (pam::PamCoupler &coupler) {dycore.timeStep(coupler);} ); if (do_density_save_recall) { pam_state_recall_dry_density(coupler); } if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"dycor"); } - if (enable_check_state) { pam_debug_check_state(coupler, 3, nstep); } + if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } // Sponge layer damping if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } coupler.run_module( "sponge_layer", modules::sponge_layer ); if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sponge"); } - if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } + // if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } // Apply hyperdiffusion to account for lack of horizontal mixing in SHOC pam_hyperdiffusion(coupler); From 0e93989e805d8ae7ecd59d2ffb955d0c10bcba30 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 15 Feb 2024 17:59:05 -0500 Subject: [PATCH 031/388] add temporary MMF_PAM_HDT for debugging --- components/eam/src/physics/crm/pam/pam_hyperdiffusion.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h index 83dc83252c6..4452c583afe 100644 --- a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h +++ b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h @@ -25,7 +25,11 @@ inline void pam_hyperdiffusion( pam::PamCoupler &coupler ) { auto uvel = dm_device.get("uvel" ); auto vvel = dm_device.get("vvel" ); //------------------------------------------------------------------------------------------------ + #ifdef MMF_PAM_HDT + real constexpr hd_timescale = MMF_PAM_HDT; // damping time scale [sec] + #else real constexpr hd_timescale = 10.0; // damping time scale [sec] + #endif //------------------------------------------------------------------------------------------------ real4d hd_temp("hd_temp",nz,ny,nx,nens); real4d hd_rhod("hd_rhod",nz,ny,nx,nens); From 047f01af0a3025d1b64d63afce65a90df2bededb Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 15 Feb 2024 17:59:38 -0500 Subject: [PATCH 032/388] Add temporary MMF_ALT_DENSITY_RECALL for debugging --- .../eam/src/physics/crm/pam/pam_state.h | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index e8f6e4ab668..34cc42a4a78 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -261,6 +261,7 @@ inline void pam_state_save_dry_density( pam::PamCoupler &coupler ) { inline void pam_state_recall_dry_density( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; + using yakl::atomicAdd; auto &dm_device = coupler.get_data_manager_device_readwrite(); auto nens = coupler.get_option("ncrms"); auto nz = coupler.get_option("crm_nz"); @@ -269,11 +270,29 @@ inline void pam_state_recall_dry_density( pam::PamCoupler &coupler ) { auto crm_rho_d = dm_device.get("density_dry"); auto tmp_rho_d = dm_device.get("density_dry_save"); //------------------------------------------------------------------------------------------------ - parallel_for( "Recall CRM dry density", - SimpleBounds<4>(nz,ny,nx,nens), - YAKL_LAMBDA (int k_crm, int j, int i, int iens) { - crm_rho_d(k_crm,j,i,iens) = tmp_rho_d(k_crm,j,i,iens); - }); + #ifdef MMF_ALT_DENSITY_RECALL + // initialize horizontal mean of previous CRM dry density + real2d old_hmean_rho_d("old_hmean_rho_d" ,nz,nens); + real2d new_hmean_rho_d("new_hmean_rho_d" ,nz,nens); + parallel_for(SimpleBounds<2>(nz,nens), YAKL_LAMBDA (int k, int iens) { + old_hmean_rho_d(k,iens) = 0; + new_hmean_rho_d(k,iens) = 0; + }); + real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions + // calculate horizontal mean of previous CRM dry density + parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { + atomicAdd( old_hmean_rho_d(k,iens), tmp_rho_d(k,j,i,iens) * r_nx_ny ); + atomicAdd( new_hmean_rho_d(k,iens), crm_rho_d(k,j,i,iens) * r_nx_ny ); + }); + // replace horizontal mean dry density with prevoius value + parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { + crm_rho_d(k,j,i,iens) = crm_rho_d(k,j,i,iens) - new_hmean_rho_d(k,iens) + old_hmean_rho_d(k,iens); + }); + #else + parallel_for( "Recall CRM dry density",SimpleBounds<4>(nz,ny,nx,nens),YAKL_LAMBDA (int k_crm, int j, int i, int iens) { + crm_rho_d(k_crm,j,i,iens) = tmp_rho_d(k_crm,j,i,iens); + }); + #endif //------------------------------------------------------------------------------------------------ } From 37062fe4288ceccb7b759d8651fd490ca9cf26bc Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 16 Feb 2024 12:08:42 -0700 Subject: [PATCH 033/388] Move pressure calc so it uses consistent time levels of variables As previously ordered, the operations in evolving waterThickness and pressure variables were out of sync, resulting in the full hydropotential variable using the old waterThickness in the term calculating the water layer elevation head. This was causing restarts with the channel model to fail and channel hydropotential gradients to be inaccurate (unknown how significant that was). This commit moves the pressure calculation to eliminate this issue. Code comments explain in more detail. --- .../mode_forward/mpas_li_subglacial_hydro.F | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index ba5a359301e..1878f4ecec7 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -543,19 +543,6 @@ subroutine li_SGH_solve(domain, err) endif - ! ============= - ! Calculate pressure field - ! ============= - block => domain % blocklist - do while (associated(block)) - - call calc_pressure(block, err_tmp) - err = ior(err, err_tmp) - - block => block % next - end do - - ! ============= ! Update water layer thickness ! ============= @@ -592,6 +579,33 @@ subroutine li_SGH_solve(domain, err) block => block % next end do + ! ============= + ! Calculate pressure field + ! ============= + ! Note: In Bueler and van Pelt, pressure is updated before waterThickness + ! (step vii on page 1625). It does not matter which order they are calculated + ! because the update calculations are formulated on intermediate variables + ! such that neither depend directly on the other in the actual update. + ! However, calc_pressure also calculates the full hydropotential (including + ! the water thickness elevation head) which *is* a direct function of water thickness, + ! making the ordering of that calculation important. + ! Because the pressure variables calculated here are meant to be used on the + ! following timestep (forward Euler), the full hydropotential should be using + ! the updated waterThickness, not the old one. To achieve that, calc_pressure + ! is called here, after waterThickness has been updated. + ! Note that the full hydropotential is only used by the channel model, so this + ! ordering choice is only needed to support channels. Without it, runs with + ! channels would use an out of date waterThickness in the hydropotential and + ! do not restart correctly due to the order of operations mismatch. + block => domain % blocklist + do while (associated(block)) + + call calc_pressure(block, err_tmp) + err = ior(err, err_tmp) + + block => block % next + end do + ! ============= ! ============= @@ -972,11 +986,11 @@ subroutine calc_edge_quantities(block, err) ! calculate magnitude of gradient of Phi gradMagPhiEdge = sqrt(hydropotentialSlopeNormal**2 + hydropotentialSlopeTangent**2) - + ! calculate magnitude of gradient of hydropotentialBase gradMagPhiBaseEdge = sqrt(hydropotentialBaseSlopeNormal**2 +& hydropotentialBaseSlopeTangent**2) - + ! calculate effective conductivity on edges if (conduc_coeff_drowned > 0.0_RKIND) then ! Use a thickness weighted conductivity coeff. when water thickness exceeds bump height From 80aa98fed9bb23f7d69b70982d82f744d0cd58eb Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 16 Feb 2024 12:24:09 -0700 Subject: [PATCH 034/388] Initialize deltatSGH only on a cold start & make it a restart variable This is needed for BFB restarts with the till model. We never use the till model, but I identified this issue while debugging channel restarts. --- components/mpas-albany-landice/src/Registry.xml | 3 ++- .../src/mode_forward/mpas_li_subglacial_hydro.F | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index 1a8523d3913..a1ddaf74401 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -869,7 +869,8 @@ - + + diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 1878f4ecec7..cffd631f00b 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -108,6 +108,7 @@ subroutine li_SGH_init(domain, err) integer, dimension(:), pointer :: cellMask real (kind=RKIND), pointer :: tillMax real (kind=RKIND), pointer :: rhoi, rhoo + logical, pointer :: config_do_restart real (kind=RKIND), pointer :: config_sea_level integer, pointer :: config_num_halos integer :: err_tmp @@ -138,6 +139,7 @@ subroutine li_SGH_init(domain, err) err = ior(err, 1) endif + call mpas_pool_get_config(liConfigs, 'config_do_restart', config_do_restart) call mpas_pool_get_config(liConfigs, 'config_SGH_till_max', tillMax) call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi) call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhoo) @@ -152,9 +154,16 @@ subroutine li_SGH_init(domain, err) call mpas_pool_get_array(hydroPool, 'deltatSGH', deltatSGH) - ! Until init is done properly, make this tiny. It will be updated at the end of the first subcycle. - ! TODO: Set time step appropriately on first subcycle of init - deltatSGH = 1.0e-4_RKIND ! in seconds + if (.not. config_do_restart) then + ! On cold start, set initial timestep to a small value. + ! On a restart we will use the value from the last subcycle of the previous + ! master timestep to make restarts BFB. + ! Note the value here is only used for the first update of thetill model; + ! the sheet and channel models calculate the adaptive timestep, but that is not + ! available for the till model as the code is currently organized. + ! TODO: Move till update until after adaptive timestep has been set + deltatSGH = 1.0e-4_RKIND ! in seconds + endif ! Mask needs to be initialized for pressure calcs to be correct call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) From 6715104cd22fe9c8d238a801f53caa64d57e3f39 Mon Sep 17 00:00:00 2001 From: Courtney Shafer Date: Tue, 27 Jun 2023 14:58:40 -0600 Subject: [PATCH 035/388] Add SGH analysis members to global stats - Add "totalSubglacialWaterVolume" - Add "totalLakeVolume" - Add "totalBasalMeltInput" - Add "totalExternalWaterInput" - Add "totalChannelMelt" - Add "totalGLMeltFlux" - Add "totalTerrestrialMeltFlux" - Add "totalChannelGLMeltFlux" - Add "totalChannelTerrestrialMeltFlux" - Add "totalFlotationFraction" - Add "avgFlotationFraction" --- .../Registry_global_stats.xml | 37 ++++ .../analysis_members/mpas_li_global_stats.F | 159 +++++++++++++++++- 2 files changed, 191 insertions(+), 5 deletions(-) mode change 100644 => 100755 components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml mode change 100644 => 100755 components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F diff --git a/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml b/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml old mode 100644 new mode 100755 index 622d33933cc..74e5875d4dd --- a/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml +++ b/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml @@ -100,6 +100,43 @@ + + + + + + + + + + + + + domain % blocklist @@ -278,6 +326,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_subpool(block % structs, 'globalStatsAM', globalStatsAMPool) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) ! get values and arrays from standard pools call mpas_pool_get_dimension(block % dimensions, 'nCellsSolve', nCellsSolve) @@ -285,6 +334,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(meshPool, 'deltat', deltat) call mpas_pool_get_array(meshPool, 'areaCell', areaCell) call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) + call mpas_pool_get_array(meshPool, 'dcEdge', dcEdge) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) @@ -299,11 +349,21 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(velocityPool, 'surfaceSpeed', surfaceSpeed) call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed) call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine) + call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) + call mpas_pool_get_array(hydroPool, 'basalMeltInput', basalMeltInput) + call mpas_pool_get_array(hydroPool, 'externalWaterInput', externalWaterInput) + call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) + call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) + call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) + call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) + call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) + call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) + ! loop over cells do iCell = 1,nCellsSolve - ! sums of ice area and volume over cells (m^2 and m^3) + ! sums of ice area and volume over cells (m^2 and m^3)i blockSumIceArea = blockSumIceArea + real(li_mask_is_ice_int(cellMask(iCell)),RKIND) & * areaCell(iCell) blockSumIceVolume = blockSumIceVolume + real(li_mask_is_ice_int(cellMask(iCell)),RKIND) & @@ -314,11 +374,13 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) blockSumGroundedIceArea = blockSumGroundedIceArea + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) & * areaCell(iCell) + blockSumGroundedIceVolume = blockSumGroundedIceVolume + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) & * areaCell(iCell) * thickness(iCell) blockSumFloatingIceArea = blockSumFloatingIceArea + real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND) & * areaCell(iCell) + blockSumFloatingIceVolume = blockSumFloatingIceVolume + real(li_mask_is_floating_ice_int(cellMask(iCell)),RKIND) & * areaCell(iCell) * thickness(iCell) @@ -335,6 +397,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) blockSumGroundedSfcMassBal = blockSumGroundedSfcMassBal + areaCell(iCell) * groundedSfcMassBalApplied(iCell) * scyr blockSumFloatingSfcMassBal = blockSumFloatingSfcMassBal + & (sfcMassBalApplied(iCell) - groundedSfcMassBalApplied(iCell)) * areaCell(iCell) * scyr + ! BMB (kg yr-1) blockSumBasalMassBal = blockSumBasalMassBal + areaCell(iCell) * basalMassBalApplied(iCell) * scyr blockSumGroundedBasalMassBal = blockSumGroundedBasalMassBal + areaCell(iCell) * groundedBasalMassBalApplied(iCell) * scyr @@ -362,13 +425,57 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) blockGLMigrationFlux = blockGLMigrationFlux + groundedToFloatingThickness(iCell) * areaCell(iCell) & * rhoi / (deltat / scyr) ! convert from m to kg/yr + !! Subglacial Hydrology Calculations + + ! Subglacial Water Volume + blockSumSubglacialWaterVolume = blockSumSubglacialWaterVolume + waterThickness(iCell) * areaCell(iCell) + + ! Basal melt input + blockSumBasalMeltInput = blockSumBasalMeltInput + basalMeltInput(iCell) * areaCell(iCell) + + ! External water input + blockSumExternalWaterInput = blockSumExternalWaterInput + externalWaterInput(iCell) * areaCell(iCell) + + ! Lake Volume + if (waterThickness(iCell) > bedBumpMax) then + blockSumLakeVolume = blockSumLakeVolume + (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) + endif + + ! Lake Area + if (waterThickness(iCell) > bedBumpMax) then + blockSumLakeArea = blockSumLakeArea + areaCell(iCell) + endif + + ! Area-weighted flotation fraction for grounded ice + if (li_mask_is_grounded_ice(cellMask(iCell))) then + blockSumFlotationFraction = blockSumFlotationFraction + ( waterPressure(iCell) / rhow / gravity / thickness(iCell) ) * areaCell(iCell) + endif + + end do ! end loop over cells ! Loop over edges do iEdge = 1, nEdgesSolve + ! Flux across GL, units = kg/yr blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) & * scyr * rhoi ! convert from m^2/s to kg/yr + + ! Channel Melt + blockSumChannelMelt = blockSumChannelMelt + abs(channelMelt(iEdge) * dcEdge(iEdge)) + + ! Meltwater Flux across the grounding line + blockSumGLMeltFlux = blockSumGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + + ! Meltwater Flux across terrestrial margins + blockSumTerrestrialMeltFlux = blockSumTerrestrialMeltFlux + abs(hydroTerrestrialMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + + ! Meltwater Discharge in channels across grounding line + blockSumChannelGLMeltFlux = blockSumChannelGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + + ! Meltwater discharge in channels across terrestrial margin + blockSumChannelTerrestrialMeltFlux = blockSumChannelTerrestrialMeltFlux + abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + end do ! end loop over edges block => block % next @@ -409,7 +516,6 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) sums(7) = blockSumSfcMassBal sums(8) = blockSumGroundedSfcMassBal sums(9) = blockSumFloatingSfcMassBal - sums(10) = blockSumBasalMassBal sums(11) = blockSumGroundedBasalMassBal sums(12) = blockSumFloatingBasalMassBal @@ -418,7 +524,18 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) sums(15) = blockSumVAF sums(16) = blockGLflux sums(17) = blockGLMigrationflux - nVars = 17 + sums(18) = blockSumSubglacialWaterVolume + sums(19) = blockSumBasalMeltInput + sums(20) = blockSumExternalWaterInput + sums(21) = blockSumChannelMelt + sums(22) = blockSumLakeVolume + sums(23) = blockSumLakeArea + sums(24) = blockSumGLMeltFlux + sums(25) = blockSumTerrestrialMeltFlux + sums(26) = blockSumChannelGLMeltFlux + sums(27) = blockSumChannelTerrestrialMeltFlux + sums(28) = blockSumFlotationFraction + nVars = 28 call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars)) @@ -447,6 +564,18 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(globalStatsAMPool, 'totalFaceMeltingFlux', totalFaceMeltingFlux) call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux) call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialWaterVolume', totalSubglacialWaterVolume) + call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMeltInput', totalBasalMeltInput) + call mpas_pool_get_array(globalStatsAMPool, 'totalExternalWaterInput', totalExternalWaterInput) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelMelt', totalChannelMelt) + call mpas_pool_get_array(globalStatsAMPool, 'totalLakeVolume', totalLakeVolume) + call mpas_pool_get_array(globalStatsAMPool, 'totalLakeArea', totalLakeArea) + call mpas_pool_get_array(globalStatsAMPool, 'totalGLMeltFlux',totalGLMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalTerrestrialMeltFlux', totalTerrestrialMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelGLMeltFlux',totalChannelGLMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelTerrestrialMeltFlux', totalChannelTerrestrialMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalFlotationFraction', totalFlotationFraction) + call mpas_pool_get_array(globalStatsAMPool, 'avgFlotationFraction', avgFlotationFraction) totalIceArea = reductions(1) totalIceVolume = reductions(2) @@ -465,6 +594,18 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) volumeAboveFloatation = reductions(15) groundingLineFlux = reductions(16) groundingLineMigrationFlux = reductions(17) + totalSubglacialWaterVolume = reductions(18) + totalBasalMeltInput = reductions(19) + totalExternalWaterInput = reductions(20) + totalChannelMelt = reductions(21) + totalLakevolume = reductions(22) + totalLakeArea = reductions(23) + totalGLMeltFlux = reductions(24) + totalTerrestrialMeltFlux = reductions(25) + totalChannelGLMeltFlux = reductions(26) + totalChannelTerrestrialMeltFlux = reductions(27) + totalFlotationFraction = reductions(28) + if (totalIceArea > 0.0_RKIND) then iceThicknessMean = totalIceVolume / totalIceArea @@ -473,17 +614,25 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) iceThicknessMean = 0.0_RKIND avgNetAccumulation = 0.0_RKIND endif + if (groundedIceArea > 0.0_RKIND) then avgGroundedBasalMelt = -1.0_RKIND * totalGroundedBasalMassBal / groundedIceArea / rhoi else avgGroundedBasalMelt = 0.0_RKIND endif + if (floatingIceArea > 0.0_RKIND) then avgSubshelfMelt = -1.0_RKIND * totalFloatingBasalMassBal / floatingIceArea / rhoi else avgSubshelfMelt = 0.0_RKIND endif + if (groundedIceArea > 0.0_RKIND) then + avgFlotationFraction = totalFlotationFraction / groundedIceArea + else + avgFlotationFraction = 0.0_RKIND + endif + block => block % next end do From f6f653c24192fbfbc2acf80419540f205db0131d Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 18 Jul 2023 18:22:18 -0600 Subject: [PATCH 036/388] Fix hydro globalStats bug - protect global stats calcs if SGH disabled Adds conditional statements in mpas_li_global_stats.F to prevent calculating SGH global stats when SGH model is deactivated. --- .../analysis_members/mpas_li_global_stats.F | 209 ++++++++++-------- 1 file changed, 112 insertions(+), 97 deletions(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F index eccc6ff36a0..2f9b75440ac 100755 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F @@ -183,6 +183,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) real (kind=RKIND), dimension(:), pointer :: basalSpeed real (kind=RKIND), dimension(:), pointer :: fluxAcrossGroundingLine real (kind=RKIND), dimension(:), pointer :: groundedToFloatingThickness + real (kind=RKIND), dimension(:), pointer :: waterThickness real (kind=RKIND), dimension(:), pointer :: basalMeltInput real (kind=RKIND), dimension(:), pointer :: externalWaterInput @@ -202,6 +203,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) real (kind=RKIND), pointer :: rhoi ! config_ice_density real (kind=RKIND), pointer :: rhow ! config_ocean_density real (kind=RKIND), pointer :: bedBumpMax ! config_SGH_bed_roughness_max + logical, pointer :: config_SGH ! Local counters integer :: k, iCell, iEdge, nCellsGrounded @@ -316,6 +318,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi) call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhow) call mpas_pool_get_config(liConfigs, 'config_SGH_bed_roughness_max', bedBumpMax) + call mpas_pool_get_config(liConfigs, 'config_SGH', config_SGH) ! loop over blocks block => domain % blocklist @@ -349,16 +352,17 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(velocityPool, 'surfaceSpeed', surfaceSpeed) call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed) call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine) - call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) - call mpas_pool_get_array(hydroPool, 'basalMeltInput', basalMeltInput) - call mpas_pool_get_array(hydroPool, 'externalWaterInput', externalWaterInput) - call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) - call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) - call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) - call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) - call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) - call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) - + if (config_SGH) then + call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) + call mpas_pool_get_array(hydroPool, 'basalMeltInput', basalMeltInput) + call mpas_pool_get_array(hydroPool, 'externalWaterInput', externalWaterInput) + call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) + call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) + call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) + call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) + call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) + call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) + endif ! loop over cells do iCell = 1,nCellsSolve @@ -426,58 +430,61 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) * rhoi / (deltat / scyr) ! convert from m to kg/yr !! Subglacial Hydrology Calculations - - ! Subglacial Water Volume - blockSumSubglacialWaterVolume = blockSumSubglacialWaterVolume + waterThickness(iCell) * areaCell(iCell) - - ! Basal melt input - blockSumBasalMeltInput = blockSumBasalMeltInput + basalMeltInput(iCell) * areaCell(iCell) - - ! External water input - blockSumExternalWaterInput = blockSumExternalWaterInput + externalWaterInput(iCell) * areaCell(iCell) - - ! Lake Volume - if (waterThickness(iCell) > bedBumpMax) then - blockSumLakeVolume = blockSumLakeVolume + (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) - endif - - ! Lake Area - if (waterThickness(iCell) > bedBumpMax) then - blockSumLakeArea = blockSumLakeArea + areaCell(iCell) + if (config_SGH) then + + ! Subglacial Water Volume + blockSumSubglacialWaterVolume = blockSumSubglacialWaterVolume + waterThickness(iCell) * areaCell(iCell) + + ! Basal melt input + blockSumBasalMeltInput = blockSumBasalMeltInput + basalMeltInput(iCell) * areaCell(iCell) + + ! External water input + blockSumExternalWaterInput = blockSumExternalWaterInput + externalWaterInput(iCell) * areaCell(iCell) + + ! Lake Volume + if (waterThickness(iCell) > bedBumpMax) then + blockSumLakeVolume = blockSumLakeVolume + (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) + endif + + ! Lake Area + if (waterThickness(iCell) > bedBumpMax) then + blockSumLakeArea = blockSumLakeArea + areaCell(iCell) + endif + + ! Area-weighted flotation fraction for grounded ice + if (li_mask_is_grounded_ice(cellMask(iCell))) then + blockSumFlotationFraction = blockSumFlotationFraction + ( waterPressure(iCell) / rhow / gravity / thickness(iCell) ) * areaCell(iCell) + endif endif - ! Area-weighted flotation fraction for grounded ice - if (li_mask_is_grounded_ice(cellMask(iCell))) then - blockSumFlotationFraction = blockSumFlotationFraction + ( waterPressure(iCell) / rhow / gravity / thickness(iCell) ) * areaCell(iCell) - endif - end do ! end loop over cells - ! Loop over edges - do iEdge = 1, nEdgesSolve - - ! Flux across GL, units = kg/yr - blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) & - * scyr * rhoi ! convert from m^2/s to kg/yr + if (config_SGH) then + ! Loop over edges + do iEdge = 1, nEdgesSolve - ! Channel Melt - blockSumChannelMelt = blockSumChannelMelt + abs(channelMelt(iEdge) * dcEdge(iEdge)) + ! Flux across GL, units = kg/yr + blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) & + * scyr * rhoi ! convert from m^2/s to kg/yr - ! Meltwater Flux across the grounding line - blockSumGLMeltFlux = blockSumGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + ! Channel Melt + blockSumChannelMelt = blockSumChannelMelt + abs(channelMelt(iEdge) * dcEdge(iEdge)) - ! Meltwater Flux across terrestrial margins - blockSumTerrestrialMeltFlux = blockSumTerrestrialMeltFlux + abs(hydroTerrestrialMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + ! Meltwater Flux across the grounding line + blockSumGLMeltFlux = blockSumGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) - ! Meltwater Discharge in channels across grounding line - blockSumChannelGLMeltFlux = blockSumChannelGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + ! Meltwater Flux across terrestrial margins + blockSumTerrestrialMeltFlux = blockSumTerrestrialMeltFlux + abs(hydroTerrestrialMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) - ! Meltwater discharge in channels across terrestrial margin - blockSumChannelTerrestrialMeltFlux = blockSumChannelTerrestrialMeltFlux + abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + ! Meltwater Discharge in channels across grounding line + blockSumChannelGLMeltFlux = blockSumChannelGLMeltFlux + abs(hydroMarineMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) - end do ! end loop over edges + ! Meltwater discharge in channels across terrestrial margin + blockSumChannelTerrestrialMeltFlux = blockSumChannelTerrestrialMeltFlux + abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + end do ! end loop over edges + endif block => block % next end do ! end loop over blocks @@ -522,20 +529,24 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) sums(13) = blockSumCalvingFlux sums(14) = blockSumFaceMeltingFlux sums(15) = blockSumVAF - sums(16) = blockGLflux - sums(17) = blockGLMigrationflux - sums(18) = blockSumSubglacialWaterVolume - sums(19) = blockSumBasalMeltInput - sums(20) = blockSumExternalWaterInput - sums(21) = blockSumChannelMelt - sums(22) = blockSumLakeVolume - sums(23) = blockSumLakeArea - sums(24) = blockSumGLMeltFlux - sums(25) = blockSumTerrestrialMeltFlux - sums(26) = blockSumChannelGLMeltFlux - sums(27) = blockSumChannelTerrestrialMeltFlux - sums(28) = blockSumFlotationFraction - nVars = 28 + if (config_SGH) then + sums(16) = blockGLflux + sums(17) = blockGLMigrationflux + sums(18) = blockSumSubglacialWaterVolume + sums(19) = blockSumBasalMeltInput + sums(20) = blockSumExternalWaterInput + sums(21) = blockSumChannelMelt + sums(22) = blockSumLakeVolume + sums(23) = blockSumLakeArea + sums(24) = blockSumGLMeltFlux + sums(25) = blockSumTerrestrialMeltFlux + sums(26) = blockSumChannelGLMeltFlux + sums(27) = blockSumChannelTerrestrialMeltFlux + sums(28) = blockSumFlotationFraction + nVars = 28 + else + nVars = 15 + endif call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars)) @@ -562,20 +573,22 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(globalStatsAMPool, 'avgSubshelfMelt', avgSubshelfMelt) call mpas_pool_get_array(globalStatsAMPool, 'totalCalvingFlux', totalCalvingFlux) call mpas_pool_get_array(globalStatsAMPool, 'totalFaceMeltingFlux', totalFaceMeltingFlux) - call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux) - call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialWaterVolume', totalSubglacialWaterVolume) - call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMeltInput', totalBasalMeltInput) - call mpas_pool_get_array(globalStatsAMPool, 'totalExternalWaterInput', totalExternalWaterInput) - call mpas_pool_get_array(globalStatsAMPool, 'totalChannelMelt', totalChannelMelt) - call mpas_pool_get_array(globalStatsAMPool, 'totalLakeVolume', totalLakeVolume) - call mpas_pool_get_array(globalStatsAMPool, 'totalLakeArea', totalLakeArea) - call mpas_pool_get_array(globalStatsAMPool, 'totalGLMeltFlux',totalGLMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalTerrestrialMeltFlux', totalTerrestrialMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalChannelGLMeltFlux',totalChannelGLMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalChannelTerrestrialMeltFlux', totalChannelTerrestrialMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalFlotationFraction', totalFlotationFraction) - call mpas_pool_get_array(globalStatsAMPool, 'avgFlotationFraction', avgFlotationFraction) + if (config_SGH) then + call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux) + call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialWaterVolume', totalSubglacialWaterVolume) + call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMeltInput', totalBasalMeltInput) + call mpas_pool_get_array(globalStatsAMPool, 'totalExternalWaterInput', totalExternalWaterInput) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelMelt', totalChannelMelt) + call mpas_pool_get_array(globalStatsAMPool, 'totalLakeVolume', totalLakeVolume) + call mpas_pool_get_array(globalStatsAMPool, 'totalLakeArea', totalLakeArea) + call mpas_pool_get_array(globalStatsAMPool, 'totalGLMeltFlux',totalGLMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalTerrestrialMeltFlux', totalTerrestrialMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelGLMeltFlux',totalChannelGLMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalChannelTerrestrialMeltFlux', totalChannelTerrestrialMeltFlux) + call mpas_pool_get_array(globalStatsAMPool, 'totalFlotationFraction', totalFlotationFraction) + call mpas_pool_get_array(globalStatsAMPool, 'avgFlotationFraction', avgFlotationFraction) + endif totalIceArea = reductions(1) totalIceVolume = reductions(2) @@ -592,20 +605,21 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) totalCalvingFlux = reductions(13) totalFaceMeltingFlux = reductions(14) volumeAboveFloatation = reductions(15) - groundingLineFlux = reductions(16) - groundingLineMigrationFlux = reductions(17) - totalSubglacialWaterVolume = reductions(18) - totalBasalMeltInput = reductions(19) - totalExternalWaterInput = reductions(20) - totalChannelMelt = reductions(21) - totalLakevolume = reductions(22) - totalLakeArea = reductions(23) - totalGLMeltFlux = reductions(24) - totalTerrestrialMeltFlux = reductions(25) - totalChannelGLMeltFlux = reductions(26) - totalChannelTerrestrialMeltFlux = reductions(27) - totalFlotationFraction = reductions(28) - + if (config_SGH) then + groundingLineFlux = reductions(16) + groundingLineMigrationFlux = reductions(17) + totalSubglacialWaterVolume = reductions(18) + totalBasalMeltInput = reductions(19) + totalExternalWaterInput = reductions(20) + totalChannelMelt = reductions(21) + totalLakevolume = reductions(22) + totalLakeArea = reductions(23) + totalGLMeltFlux = reductions(24) + totalTerrestrialMeltFlux = reductions(25) + totalChannelGLMeltFlux = reductions(26) + totalChannelTerrestrialMeltFlux = reductions(27) + totalFlotationFraction = reductions(28) + endif if (totalIceArea > 0.0_RKIND) then iceThicknessMean = totalIceVolume / totalIceArea @@ -626,11 +640,12 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) else avgSubshelfMelt = 0.0_RKIND endif - - if (groundedIceArea > 0.0_RKIND) then - avgFlotationFraction = totalFlotationFraction / groundedIceArea - else - avgFlotationFraction = 0.0_RKIND + if (config_SGH) then + if (groundedIceArea > 0.0_RKIND) then + avgFlotationFraction = totalFlotationFraction / groundedIceArea + else + avgFlotationFraction = 0.0_RKIND + endif endif block => block % next From d31ecb0dddd700b18134ed0d81e1bdc0bcaa472a Mon Sep 17 00:00:00 2001 From: Courtney Shafer Date: Tue, 11 Jul 2023 13:53:38 -0600 Subject: [PATCH 037/388] Add grounded ice mask to BasalMeltInput term The basalMeltInput term was including non-grounded ice in the calculation of the totalBasalMeltInput and giving wrong answers. The mask ensures that only basal melt occurring under grounded ice is considered. --- .../src/analysis_members/mpas_li_global_stats.F | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F index 2f9b75440ac..0579ebe7cde 100755 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F @@ -436,7 +436,8 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) blockSumSubglacialWaterVolume = blockSumSubglacialWaterVolume + waterThickness(iCell) * areaCell(iCell) ! Basal melt input - blockSumBasalMeltInput = blockSumBasalMeltInput + basalMeltInput(iCell) * areaCell(iCell) + blockSumBasalMeltInput = blockSumBasalMeltInput + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * & + basalMeltInput(iCell) * areaCell(iCell) ! External water input blockSumExternalWaterInput = blockSumExternalWaterInput + externalWaterInput(iCell) * areaCell(iCell) @@ -648,6 +649,8 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) endif endif + + block => block % next end do From 48b1edb27c1a489d991b55ff4c8d78b68ded1bbe Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Sat, 17 Feb 2024 12:49:20 -0700 Subject: [PATCH 038/388] Update variable names and other code review edits --- .../Registry_global_stats.xml | 32 +++++------ .../analysis_members/mpas_li_global_stats.F | 55 +++++++++---------- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml b/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml index 74e5875d4dd..50ad7915835 100755 --- a/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml +++ b/components/mpas-albany-landice/src/analysis_members/Registry_global_stats.xml @@ -100,14 +100,15 @@ + - - - - - - - - + bedBumpMax) then blockSumLakeVolume = blockSumLakeVolume + (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) endif - + ! Lake Area if (waterThickness(iCell) > bedBumpMax) then blockSumLakeArea = blockSumLakeArea + areaCell(iCell) @@ -581,13 +581,12 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMeltInput', totalBasalMeltInput) call mpas_pool_get_array(globalStatsAMPool, 'totalExternalWaterInput', totalExternalWaterInput) call mpas_pool_get_array(globalStatsAMPool, 'totalChannelMelt', totalChannelMelt) - call mpas_pool_get_array(globalStatsAMPool, 'totalLakeVolume', totalLakeVolume) - call mpas_pool_get_array(globalStatsAMPool, 'totalLakeArea', totalLakeArea) - call mpas_pool_get_array(globalStatsAMPool, 'totalGLMeltFlux',totalGLMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalTerrestrialMeltFlux', totalTerrestrialMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalChannelGLMeltFlux',totalChannelGLMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalChannelTerrestrialMeltFlux', totalChannelTerrestrialMeltFlux) - call mpas_pool_get_array(globalStatsAMPool, 'totalFlotationFraction', totalFlotationFraction) + call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialLakeVolume', totalSubglacialLakeVolume) + call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialLakeArea', totalSubglacialLakeArea) + call mpas_pool_get_array(globalStatsAMPool, 'totalDistWaterFluxMarineMargin',totalDistWaterFluxMarineMargin) + call mpas_pool_get_array(globalStatsAMPool, 'totalDistWaterFluxTerrestrialMargin', totalDistWaterFluxTerrestrialMargin) + call mpas_pool_get_array(globalStatsAMPool, 'totalChnlWaterFluxMarineMargin',totalChnlWaterFluxMarineMargin) + call mpas_pool_get_array(globalStatsAMPool, 'totalChnlWaterFluxTerrestrialMargin', totalChnlWaterFluxTerrestrialMargin) call mpas_pool_get_array(globalStatsAMPool, 'avgFlotationFraction', avgFlotationFraction) endif @@ -613,12 +612,12 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) totalBasalMeltInput = reductions(19) totalExternalWaterInput = reductions(20) totalChannelMelt = reductions(21) - totalLakevolume = reductions(22) - totalLakeArea = reductions(23) - totalGLMeltFlux = reductions(24) - totalTerrestrialMeltFlux = reductions(25) - totalChannelGLMeltFlux = reductions(26) - totalChannelTerrestrialMeltFlux = reductions(27) + totalSubglacialLakeVolume = reductions(22) + totalSubglacialLakeArea = reductions(23) + totalDistWaterFluxMarineMargin = reductions(24) + totalDistWaterFluxTerrestrialMargin = reductions(25) + totalChnlWaterFluxMarineMargin = reductions(26) + totalChnlWaterFluxTerrestrialMargin = reductions(27) totalFlotationFraction = reductions(28) endif From 32f22cf5dfd67807a3becdf43e550f17bb918fb0 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Sat, 17 Feb 2024 13:13:39 -0700 Subject: [PATCH 039/388] Correct flotation fraction globalStat to use ice density --- .../src/analysis_members/mpas_li_global_stats.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F index fae83093017..2e1d05cbc39 100755 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F @@ -454,7 +454,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) ! Area-weighted flotation fraction for grounded ice if (li_mask_is_grounded_ice(cellMask(iCell))) then - blockSumFlotationFraction = blockSumFlotationFraction + ( waterPressure(iCell) / rhow / gravity / thickness(iCell) ) * areaCell(iCell) + blockSumFlotationFraction = blockSumFlotationFraction + ( waterPressure(iCell) / rhoi / gravity / thickness(iCell) ) * areaCell(iCell) endif endif From 087aace29c8a941147fdedc76a6f00808a9ff06c Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 10:22:35 -0700 Subject: [PATCH 040/388] Improve synchronization of timesteps between MALI and SLM This PR updates handling of timesteps between MALI and the SLM in a few ways: * switch config_slm_coupling_interval to be an integer in years because we only allow integer year values * On init, check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval * On init, check that restart interval is an even multiple of config_slm_coupling_interval * On a restart, calculate which SLM time level to use based on the elapsed time from the start of the original simulation and config_slm_coupling_interval and make sure these divide cleanly --- .../mpas-albany-landice/src/Registry.xml | 10 +- .../src/mode_forward/mpas_li_bedtopo.F | 232 ++++++++++++++---- 2 files changed, 188 insertions(+), 54 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index c4cd6df05bb..1c6e0f63298 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -145,13 +145,9 @@ description="Selection of the method for bedrock uplift calculation." possible_values="'none', 'data', 'sealevelmodel'" /> - - \brief Perform various checks on the SLM coupling interval setting +!> \author Matt Hoffman +!> \date Feb 2024 +!> \details +!> This routine checks that the SLM coupling interval is an even multiple +!> of the adaptive timestep force inverval and divides evenly into the +!> restart interval. It also checks that the coupling interval in the MALI +!> matches the value in the SLM namelist. +! +!----------------------------------------------------------------------- + + subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) + + use mpas_timekeeping + use mpas_stream_manager + use mpas_derived_types, only : MPAS_STREAM_PROPERTY_RECORD_INTV + + integer, intent (in) :: slm_dt1 + type (MPAS_streamManager_type), intent(inout) :: streamManager + integer, intent(out) :: err + + ! local variables + integer, pointer :: config_slm_coupling_interval + character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval + type (MPAS_Time_Type) :: force_interval, restart_interval + character(len=StrKIND) :: restart_interval_str + integer :: YYYY, MM, DD, H, M, S ! time components + type (MPAS_stream_list_type), pointer :: stream_cursor + integer :: err_tmp + + err = 0 + + ! First, check consistency in coupling interval set up in MALI and SLM + call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + if (config_slm_coupling_interval /= slm_dt1) then + call mpas_log_write("The coupling interval in MALI and SLM settings are inconsistent", MPAS_LOG_ERR) + err = ior(err,1) + endif + + ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) + ! Note: Using mpas_set_time instead of mpas_set_time_interval, even though this is an interval + ! This is because mpas_get_time_interval requires a reference time, which is not relevant + ! to these checks, and mpas_get_time allows us to get the component pieces that we want to check. + call mpas_set_time(force_interval, dateTimeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(force_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & + "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & + "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) + ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval + ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. + err = ior(err, 1) + endif + ! Next check the number of years divides evenly into SLM coupling interval + if (mod(config_slm_coupling_interval, YYYY) /= 0) then + call mpas_log_write("config_adaptive_timestep_force_interval does not divide evenly into config_slm_coupling_interval" // & + "config_adaptive_timestep_force_interval=" // trim(config_adaptive_timestep_force_interval) // & + "; config_slm_coupling_interval=$i", MPAS_LOG_ERR, intArgs=(/config_slm_coupling_interval/)) + err = ior(err, 1) + endif + + ! Now check that restart interval is an even multiple of coupling interval + stream_cursor => streamManager % streams % head + do while (associated(stream_cursor)) + if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % valid) ) then + call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & + restart_interval_str, ierr=err_tmp) + err = ior(err, err_tmp) + + call mpas_log_write('restart interval is: ' //trim(restart_interval_str)) + + call mpas_set_time(restart_interval, dateTimeString=restart_interval_str, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(restart_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & + "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & + trim(restart_interval_str), MPAS_LOG_ERR) + endif + err = ior(err, 1) + + if (mod(YYYY, config_slm_coupling_interval) /= 0) then + call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + endif + enddo + + !-------------------------------------------------------------------- + end subroutine check_SLM_coupling_interval + + +!*********************************************************************** +! +! routine find_slm_restart_timestep +! +!> \brief Perform various checks on the SLM coupling interval setting +!> \author Matt Hoffman +!> \date Feb 2024 +!> \details +!> This routine checks that the SLM coupling interval is an even multiple +!> of the adaptive timestep force inverval and divides evenly into the +!> restart interval. It also checks that the coupling interval in the MALI +!> matches the value in the SLM namelist. +! +!----------------------------------------------------------------------- + + subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) + + use mpas_timekeeping + + type (mpas_pool_type), intent(in) :: meshPool !< mesh information + integer, intent(out) :: slmTimeStep + integer, intent(out) :: err + + ! local vars + integer, pointer :: config_slm_coupling_interval + character (len=StrKIND), pointer :: xtime, simulationStartTime + character (len=StrKIND) :: elapsed_time_str + type (MPAS_Time_Type) :: start_time, curr_time + type (MPAS_Time_Type) :: elapsed_time ! should be a time interval but not possible to get years that way + integer :: YYYY, MM, DD, H, M, S ! time components + integer :: err_tmp + + err = 0 + + slmTimeStep = -999 ! initialize to bad number + + call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_pool_get_array(meshPool, 'xtime', xtime) + call mpas_set_time(start_time, dateTimeString=simulationStartTime, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_set_time(curr_time, dateTimeString=xtime, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_timeInterval(curr_time - start_time, start_time, timeString=elapsed_time_str, ierr=err_tmp) + err = ior(err, err_tmp) + + ! convert elapsed time string to its units. Using the intermediate string format because mpas_get_timeInterval doesn't return + ! years, and figuring out years from days depends on the calendar + call mpas_set_time(elapsed_time, dateTimeString=elapsed_time_str, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_get_time(elapsed_time, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) + + ! make sure the elapsed time is an even year + if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then + call mpas_log_write("Elapsed time since simulationStartTime include nonzero months, days, hours, minutes, " // & + "or seconds.", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + if (mod(YYYY, config_slm_coupling_interval) == 0) then + ! We can restart cleanly + slmTimeStep = YYYY / config_slm_coupling_interval + else + call mpas_log_write("Elapsed years since simulationStartTime is not evenly divisible by config_slm_coupling_interval." // & + " Unable to restart Sea Level Model cleanly.", MPAS_LOG_ERR) + err = ior(err, 1) + endif + + !-------------------------------------------------------------------- + end subroutine find_slm_restart_timestep + !*********************************************************************** end module li_bedtopo From 55e579bfe8ade495499de24aa3922bc3f4c59989 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 12:19:20 -0700 Subject: [PATCH 041/388] Improve error handling, correct other usage of config_uplift_method Also add missing =>next pointer assignment to keep code from hanging --- .../src/mode_forward/mpas_li_bedtopo.F | 42 +++++++++++++------ .../src/mode_forward/mpas_li_core.F | 11 ++--- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 9a5cc0ad32a..b9a09ed5f9c 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -115,6 +115,7 @@ subroutine li_bedtopo_init(domain, err) !----------------------------------------------------------------- character (len=StrKIND), pointer :: config_uplift_method + integer :: err_tmp ! No init is needed. err = 0 @@ -122,7 +123,12 @@ subroutine li_bedtopo_init(domain, err) call mpas_pool_get_config(liConfigs, 'config_uplift_method', config_uplift_method) if (trim(config_uplift_method)=='sealevelmodel') then ! initialize the 1D sea-level model if fresh start - call slmodel_init(domain, err) + call slmodel_init(domain, err_tmp) + err = ior(err, err_tmp) + + if (err /= 0) then + call mpas_log_write('Error in li_bedtopo_init', MPAS_LOG_ERR) + endif endif !-------------------------------------------------------------------- @@ -445,7 +451,7 @@ subroutine slmodel_init(domain, err) call check_SLM_coupling_interval(dtime, domain % streamManager, err_tmp) err = ior(err, err_tmp) if (err /= 0) then - return + call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) endif ! Set Displacement variable for GATHERV command @@ -473,8 +479,10 @@ subroutine slmodel_init(domain, err) call find_slm_restart_timestep(meshPool, slmTimeStep, err_tmp) err = ior(err, err_tmp) - call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) - call slmodel_solve(slmTimeStep, domain) + if (err == 0) then + call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) + call slmodel_solve(slmTimeStep, domain) + endif else @@ -532,11 +540,13 @@ subroutine slmodel_init(domain, err) slmTimeStep = 0 ! series of calling SLM routines - call sl_call_readnl - call sl_solver_checkpoint(itersl, dtime) - call sl_timewindow(slmTimeStep) - call sl_solver_init(itersl, starttime, ismIceload, ismBedtopo, ismMask) - call sl_deallocate_array + if (err == 0) then + call sl_call_readnl + call sl_solver_checkpoint(itersl, dtime) + call sl_timewindow(slmTimeStep) + call sl_solver_init(itersl, starttime, ismIceload, ismBedtopo, ismMask) + call sl_deallocate_array + endif endif deallocate(globalArrayThickness) @@ -995,12 +1005,14 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) integer :: err_tmp err = 0 + err_tmp = 0 ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) if (config_slm_coupling_interval /= slm_dt1) then - call mpas_log_write("The coupling interval in MALI and SLM settings are inconsistent", MPAS_LOG_ERR) - err = ior(err,1) + call mpas_log_write("The coupling interval in MALI ($i) and SLM ($i) are inconsistent", MPAS_LOG_ERR, & + intArgs=(/config_slm_coupling_interval, slm_dt1/)) + err = ior(err, 1) endif ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval @@ -1015,6 +1027,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) + call mpas_log_write(" MM=$i, DD=$i, H=$i, M=$i, S=$i", intArgs=(/MM, DD, H, M, S/)) ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. err = ior(err, 1) @@ -1030,7 +1043,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) ! Now check that restart interval is an even multiple of coupling interval stream_cursor => streamManager % streams % head do while (associated(stream_cursor)) - if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % valid) ) then + if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then + call mpas_log_write("Checking restart interval against SLM coulping interval") call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & restart_interval_str, ierr=err_tmp) err = ior(err, err_tmp) @@ -1044,8 +1058,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & trim(restart_interval_str), MPAS_LOG_ERR) + err = ior(err, 1) endif - err = ior(err, 1) if (mod(YYYY, config_slm_coupling_interval) /= 0) then call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) @@ -1053,6 +1067,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) endif endif + + stream_cursor => stream_cursor % next enddo !-------------------------------------------------------------------- diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F index 10ee1e94b30..146b4e36d80 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F @@ -338,8 +338,8 @@ function li_core_init(domain, startTimeStamp) result(err) ! === call li_velocity_external_write_albany_mesh(domain) - call mpas_dmpar_max_int(domain % dminfo, err, globalErr) ! Find out if any blocks got an error - if (globalErr > 0) then + call mpas_dmpar_max_int(domain % dminfo, abs(err), globalErr) ! Find out if any blocks got an error + if (globalErr /= 0) then call mpas_log_write("An error has occurred in li_core_init. Aborting...", MPAS_LOG_CRIT) endif @@ -1111,7 +1111,8 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) character (len=StrKIND), pointer :: config_dt ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_restart_timestamp_name - character (len=StrKIND), pointer :: config_uplift_method, config_slm_coupling_interval + character (len=StrKIND), pointer :: config_uplift_method + integer, pointer :: config_slm_coupling_interval character (len=StrKIND) :: restartTimeStamp !< string to be read from file integer, pointer :: config_year_digits integer :: err_tmp @@ -1197,7 +1198,7 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) ! Set up the coupling time interval if MALI is coupled to sea-level model if (trim(config_uplift_method) == "sealevelmodel") then - call mpas_set_timeInterval(slm_coupling_interval, timeString=config_slm_coupling_interval, ierr=err_tmp) + call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) ierr = ior(ierr,err_tmp) call mpas_add_clock_alarm(core_clock, 'slmCouplingInterval', alarmTime=startTime, & alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) @@ -1210,7 +1211,7 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) endif ! === error check - if (ierr > 0) then + if (ierr /= 0) then call mpas_log_write("An error has occurred in li_simulation_clock_init.", MPAS_LOG_ERR) endif From 32ff9f8e24f32a2b4a768d526397751e41f25357 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:17:55 -0700 Subject: [PATCH 042/388] Update checks using interval division Trying to cast intervals into dateTimeStrings did not work. --- .../src/mode_forward/mpas_li_bedtopo.F | 75 ++++++++----------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index b9a09ed5f9c..dbdcb43d3aa 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -448,7 +448,7 @@ subroutine slmodel_init(domain, err) call sl_drive_readnl(itersl, dtime, starttime) !SLM subroutine ! First, check consistency in coupling interval set up in MALI and SLM - call check_SLM_coupling_interval(dtime, domain % streamManager, err_tmp) + call check_SLM_coupling_interval(dtime, meshPool, domain % streamManager, err_tmp) err = ior(err, err_tmp) if (err /= 0) then call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) @@ -985,23 +985,27 @@ end subroutine check ! !----------------------------------------------------------------------- - subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) + subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) use mpas_timekeeping use mpas_stream_manager use mpas_derived_types, only : MPAS_STREAM_PROPERTY_RECORD_INTV integer, intent (in) :: slm_dt1 + type (mpas_pool_type), intent(in) :: meshPool !< mesh information type (MPAS_streamManager_type), intent(inout) :: streamManager integer, intent(out) :: err ! local variables integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval - type (MPAS_Time_Type) :: force_interval, restart_interval - character(len=StrKIND) :: restart_interval_str + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, restart_interval, zero_interval + type (MPAS_Time_Type) :: start_time + character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components type (MPAS_stream_list_type), pointer :: stream_cursor + integer (kind=I8KIND) :: n_intervals + type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp err = 0 @@ -1015,28 +1019,26 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) err = ior(err, 1) endif + ! define zero interval for comparing against below + call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) + ! get start time as a reference time + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_set_time(start_time, dateTimeString=simulationStartTime) + ! define SLM coupling interval as a timeInterval type + call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) + err = ior(err, err_tmp) + ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) - ! Note: Using mpas_set_time instead of mpas_set_time_interval, even though this is an interval - ! This is because mpas_get_time_interval requires a reference time, which is not relevant - ! to these checks, and mpas_get_time allows us to get the component pieces that we want to check. - call mpas_set_time(force_interval, dateTimeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_time(force_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("config_adaptive_timestep_force_interval currently not supported " // & - "to have nonzero values for months, days, hours, minutes, or seconds when sea-level model " // & - "is coupled. config_adaptive_timestep_force_interval=" //trim(config_adaptive_timestep_force_interval), MPAS_LOG_ERR) - call mpas_log_write(" MM=$i, DD=$i, H=$i, M=$i, S=$i", intArgs=(/MM, DD, H, M, S/)) - ! Note: the actual requirement is that adapt dt force interval divides evenly into coupling interval - ! but that is tricky to check, and wanting anything but even years for that option is a rare use case. - err = ior(err, 1) - endif - ! Next check the number of years divides evenly into SLM coupling interval - if (mod(config_slm_coupling_interval, YYYY) /= 0) then - call mpas_log_write("config_adaptive_timestep_force_interval does not divide evenly into config_slm_coupling_interval" // & - "config_adaptive_timestep_force_interval=" // trim(config_adaptive_timestep_force_interval) // & - "; config_slm_coupling_interval=$i", MPAS_LOG_ERR, intArgs=(/config_slm_coupling_interval/)) + call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) err = ior(err, 1) endif @@ -1045,27 +1047,16 @@ subroutine check_SLM_coupling_interval(slm_dt1, streamManager, err) do while (associated(stream_cursor)) if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then call mpas_log_write("Checking restart interval against SLM coulping interval") - call MPAS_stream_mgr_get_property(streamManager, 'restart', MPAS_STREAM_PROPERTY_RECORD_INTV, & - restart_interval_str, ierr=err_tmp) - err = ior(err, err_tmp) - - call mpas_log_write('restart interval is: ' //trim(restart_interval_str)) - - call mpas_set_time(restart_interval, dateTimeString=restart_interval_str, ierr=err_tmp) + restart_interval = MPAS_stream_mgr_get_stream_interval(streamManager, 'restart', MPAS_STREAM_OUTPUT, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_time(restart_interval, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("If Sea Level Model is active, restart output_interval cannot include " // & - "nonzero months, days, hours, minutes or seconds. restart output_interval=" // & - trim(restart_interval_str), MPAS_LOG_ERR) - err = ior(err, 1) + call mpas_interval_division(start_time, restart_interval, coupling_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) endif - - if (mod(YYYY, config_slm_coupling_interval) /= 0) then - call mpas_log_write("restart output_interval must be a multiple of config_slm_coupling_interval", MPAS_LOG_ERR) - err = ior(err, 1) - endif - endif stream_cursor => stream_cursor % next From 869f944989932fb7b33822a2735fd70d5cf61cae Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:35:41 -0700 Subject: [PATCH 043/388] Adjust check if adaptive dt is on or not --- .../src/mode_forward/mpas_li_bedtopo.F | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index dbdcb43d3aa..facbf8e9d6d 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -998,8 +998,9 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) ! local variables integer, pointer :: config_slm_coupling_interval - character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval - type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, restart_interval, zero_interval + logical, pointer :: config_adaptive_timestep + character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval, config_dt + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, restart_interval, zero_interval type (MPAS_Time_Type) :: start_time character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components @@ -1011,10 +1012,15 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) err = 0 err_tmp = 0 + call mpas_log_write("") + call mpas_log_write("-- Checking consistency of config_slm_coupling_interval and other settings --") + ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) - if (config_slm_coupling_interval /= slm_dt1) then - call mpas_log_write("The coupling interval in MALI ($i) and SLM ($i) are inconsistent", MPAS_LOG_ERR, & + if (config_slm_coupling_interval == slm_dt1) then + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes") + else + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are inconsistent", MPAS_LOG_ERR, & intArgs=(/config_slm_coupling_interval, slm_dt1/)) err = ior(err, 1) endif @@ -1028,18 +1034,35 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) err = ior(err, err_tmp) - ! Check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval - call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) - call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) - if (remainder .EQ. zero_interval) then - call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep", config_adaptive_timestep) + if (config_adaptive_timestep) then + ! for adaptive dt, check that config_adaptive_timestep_force_interval divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_adaptive_timestep_force_interval", config_adaptive_timestep_force_interval) + call mpas_set_timeInterval(force_interval, timeString=config_adaptive_timestep_force_interval, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_interval_division(start_time, coupling_interval, force_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) + err = ior(err, 1) + endif else - call mpas_log_write("config_adaptive_timestep_force_interval divides into config_slm_coupling_interval $i times " // & + ! For fixed dt, check that dt divides evenly into config_slm_coupling_interval + call mpas_pool_get_config(liConfigs, "config_dt", config_dt) + call mpas_set_timeInterval(dt_interval, timeString=config_dt, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_interval_division(start_time, coupling_interval, dt_interval, n_intervals, remainder) + if (remainder .EQ. zero_interval) then + call mpas_log_write("config_dt divides into config_slm_coupling_interval $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + else + call mpas_log_write("config_dt divides into config_slm_coupling_interval $i times " // & "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) + err = ior(err, 1) + endif endif ! Now check that restart interval is an even multiple of coupling interval @@ -1061,6 +1084,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) stream_cursor => stream_cursor % next enddo + call mpas_log_write("") !-------------------------------------------------------------------- end subroutine check_SLM_coupling_interval From a4d0d68995bcc4ca94d12c4b780640e874a3ad66 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:48:16 -0700 Subject: [PATCH 044/388] Update restart check to also use time interval division --- .../src/mode_forward/mpas_li_bedtopo.F | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index facbf8e9d6d..24fee4d71a2 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1116,17 +1116,20 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) ! local vars integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: xtime, simulationStartTime - character (len=StrKIND) :: elapsed_time_str + type (MPAS_TimeInterval_Type) :: coupling_interval, zero_interval type (MPAS_Time_Type) :: start_time, curr_time - type (MPAS_Time_Type) :: elapsed_time ! should be a time interval but not possible to get years that way - integer :: YYYY, MM, DD, H, M, S ! time components + integer (kind=I8KIND) :: n_intervals + type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp err = 0 - - slmTimeStep = -999 ! initialize to bad number + err_tmp = 0 call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) + ! define SLM coupling interval as a timeInterval type + call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) call mpas_pool_get_array(meshPool, 'xtime', xtime) @@ -1134,30 +1137,20 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) err = ior(err, err_tmp) call mpas_set_time(curr_time, dateTimeString=xtime, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_get_timeInterval(curr_time - start_time, start_time, timeString=elapsed_time_str, ierr=err_tmp) - err = ior(err, err_tmp) - - ! convert elapsed time string to its units. Using the intermediate string format because mpas_get_timeInterval doesn't return - ! years, and figuring out years from days depends on the calendar - call mpas_set_time(elapsed_time, dateTimeString=elapsed_time_str, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_get_time(elapsed_time, YYYY=YYYY, MM=MM, DD=DD, H=H, M=M, S=S) - - ! make sure the elapsed time is an even year - if ((MM /= 0) .or. (DD /= 0) .or. (H /= 0) .or. (M /= 0) .or. (S /= 0)) then - call mpas_log_write("Elapsed time since simulationStartTime include nonzero months, days, hours, minutes, " // & - "or seconds.", MPAS_LOG_ERR) - err = ior(err, 1) - endif - if (mod(YYYY, config_slm_coupling_interval) == 0) then - ! We can restart cleanly - slmTimeStep = YYYY / config_slm_coupling_interval + call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) + call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) + if (remainder .EQ. zero_interval) then + call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & + "with no remainder - check passes", intArgs=(/int(n_intervals)/)) + slmTimeStep = int(n_intervals) else - call mpas_log_write("Elapsed years since simulationStartTime is not evenly divisible by config_slm_coupling_interval." // & - " Unable to restart Sea Level Model cleanly.", MPAS_LOG_ERR) + call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & + "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) err = ior(err, 1) + slmTimeStep = -999 endif + call mpas_log_write("") !-------------------------------------------------------------------- end subroutine find_slm_restart_timestep From a3c43371b118fc9b14ad66e36a4aad1b7b06427a Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Wed, 21 Feb 2024 13:57:09 -0700 Subject: [PATCH 045/388] Add missing arguments to log write statement --- .../mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 24fee4d71a2..aacfbed95ad 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1018,7 +1018,8 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) ! First, check consistency in coupling interval set up in MALI and SLM call mpas_pool_get_config(liConfigs, "config_slm_coupling_interval", config_slm_coupling_interval) if (config_slm_coupling_interval == slm_dt1) then - call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes") + call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are consistent - check passes", & + intArgs=(/config_slm_coupling_interval, slm_dt1/)) else call mpas_log_write("The coupling interval in MALI ($i yr) and SLM ($i yr) are inconsistent", MPAS_LOG_ERR, & intArgs=(/config_slm_coupling_interval, slm_dt1/)) From c692d660715f555fdb70014cb7febe138b8763ea Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Wed, 21 Feb 2024 16:41:27 -0700 Subject: [PATCH 046/388] Add support for subglacial hydro quantities in regional stats. Following the recent addition of subglacial hydro quantities to the global stats analysis member, we've used those additions as template to add the quantitites to the regional stats analysis member. --- .../Registry_regional_stats.xml | 35 +++ .../analysis_members/mpas_li_regional_stats.F | 207 +++++++++++++++++- 2 files changed, 238 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/analysis_members/Registry_regional_stats.xml b/components/mpas-albany-landice/src/analysis_members/Registry_regional_stats.xml index 7ae1f284d1d..8434ff36a81 100644 --- a/components/mpas-albany-landice/src/analysis_members/Registry_regional_stats.xml +++ b/components/mpas-albany-landice/src/analysis_members/Registry_regional_stats.xml @@ -103,6 +103,41 @@ description="maximum basal speed in the domain" /> + + + + + + + + + + + + + diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F index 0f544b4b47a..be9b5c8a255 100644 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F @@ -164,12 +164,14 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) type (mpas_pool_type), pointer :: geometryPool type (mpas_pool_type), pointer :: regionsPool type (mpas_pool_type), pointer :: velocityPool + type (mpas_pool_type), pointer :: hydroPool ! arrays, vars needed from other pools for calculations here real (kind=RKIND), pointer :: config_ice_density real (kind=RKIND), pointer :: deltat real (kind=RKIND), dimension(:), pointer :: areaCell real (kind=RKIND), dimension(:), pointer :: dvEdge + real (kind=RKIND), dimension(:), pointer :: dcEdge real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: sfcMassBalApplied @@ -185,15 +187,27 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) real (kind=RKIND), dimension(:), pointer :: groundedToFloatingThickness real (kind=RKIND), dimension(:,:), pointer :: normalVelocity + real (kind=RKIND), dimension(:), pointer :: waterThickness + real (kind=RKIND), dimension(:), pointer :: basalMeltInput + real (kind=RKIND), dimension(:), pointer :: externalWaterInput + real (kind=RKIND), dimension(:), pointer :: channelMelt + real (kind=RKIND), dimension(:), pointer :: waterFlux + real (kind=RKIND), dimension(:), pointer :: channelDischarge + real (kind=RKIND), dimension(:), pointer :: waterPressure + ! config options needed real (kind=RKIND), pointer :: config_sea_level real (kind=RKIND), pointer :: rhoi ! config_ice_density real (kind=RKIND), pointer :: rhow ! config_ocean_density + real (kind=RKIND), pointer :: bedBumpMax ! config_SGH_bed_roughness_max + logical, pointer :: config_SGH integer, dimension(:,:), pointer :: regionCellMasks integer, dimension(:), pointer :: cellMask integer, dimension(:), pointer :: edgeMask integer, dimension(:,:), pointer :: cellsOnEdge + integer, dimension(:), pointer :: hydroMarineMarginMask + integer, dimension(:), pointer :: hydroTerrestrialMarginMask integer, pointer :: nRegions, nRegionGroups !, maxRegionsInGroup !! maxRegionsInGroup not needed / used yet integer, pointer :: nCellsSolve, nEdgesSolve, nVertLevels integer :: k, iCell, iEdge @@ -218,6 +232,17 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) real (kind=RKIND), dimension(:), pointer :: regionalAvgSubshelfMelt real (kind=RKIND), dimension(:), pointer :: regionalSurfaceSpeedMax real (kind=RKIND), dimension(:), pointer :: regionalBasalSpeedMax + real (kind=RKIND), dimension(:), pointer :: regionalSumSubglacialWaterVolume + real (kind=RKIND), dimension(:), pointer :: regionalSumBasalMeltInput + real (kind=RKIND), dimension(:), pointer :: regionalSumExternalWaterInput + real (kind=RKIND), dimension(:), pointer :: regionalSumChannelMelt + real (kind=RKIND), dimension(:), pointer :: regionalSumSubglacialLakeVolume + real (kind=RKIND), dimension(:), pointer :: regionalSumSubglacialLakeArea + real (kind=RKIND), dimension(:), pointer :: regionalSumDistWaterFluxMarineMargin + real (kind=RKIND), dimension(:), pointer :: regionalSumDistWaterFluxTerrestrialMargin + real (kind=RKIND), dimension(:), pointer :: regionalSumChnlWaterFluxMarineMargin + real (kind=RKIND), dimension(:), pointer :: regionalSumChnlWaterFluxTerrestrialMargin + real (kind=RKIND), dimension(:), pointer :: regionalAvgFlotationFraction ! storage for sums over blocks real (kind=RKIND), dimension(:), allocatable :: blockSumRegionIceArea, blockSumRegionIceVolume @@ -234,12 +259,25 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) real (kind=RKIND), dimension(:), allocatable :: blockRegionGLMigrationFlux real (kind=RKIND), dimension(:), allocatable :: blockRegionMaxSurfaceSpeed real (kind=RKIND), dimension(:), allocatable :: blockRegionMaxBasalSpeed + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionSubglacialWaterVolume + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionBasalMeltInput + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionExternalWaterInput + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionChannelMelt + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionLakeVolume + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionLakeArea + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionGLMeltFlux + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionTerrestrialMeltFlux + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionChannelGLMeltFlux + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionChannelTerrestrialMeltFlux + real (kind=RKIND), dimension(:), allocatable :: blockSumRegionFlotationFraction + ! local variable needed calculating average floation fraction in a region + real (kind=RKIND), dimension(:), allocatable:: regionalSumFlotationFraction ! local variables real (kind=RKIND) :: fluxSign ! variables for processing stats - integer, parameter :: kMaxVariables = 32 ! Increase if number of stats increase + integer, parameter :: kMaxVariables = 43 ! Increase if number of stats increase integer :: nVars real (kind=RKIND), dimension(kMaxVariables) :: reductions, sums, mins, maxes @@ -251,6 +289,8 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi) call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhow) + call mpas_pool_get_config(liConfigs, 'config_SGH_bed_roughness_max', bedBumpMax) + call mpas_pool_get_config(liConfigs, 'config_SGH', config_SGH) ! loop over blocks block => domain % blocklist @@ -265,7 +305,8 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call mpas_pool_get_subpool(block % structs, 'regions', regionsPool) -! call mpas_pool_get_subpool(block % structs, 'regionalStatsAM', regionalStatsAMPool) + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) +! call mpas_pool_get_subpool(block % structs, 'regionalStatsAM', regionalStatsAMPool) ! get values and arrays from standard pools call mpas_pool_get_config(liConfigs, 'config_ice_density', config_ice_density) @@ -292,6 +333,18 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(velocityPool, 'basalSpeed', basalSpeed) call mpas_pool_get_array(velocityPool, 'fluxAcrossGroundingLine', fluxAcrossGroundingLine) call mpas_pool_get_array(velocityPool, 'normalVelocity', normalVelocity) + if (config_SGH) then + call mpas_pool_get_array(meshPool, 'dcEdge', dcEdge) + call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) + call mpas_pool_get_array(hydroPool, 'basalMeltInput', basalMeltInput) + call mpas_pool_get_array(hydroPool, 'externalWaterInput', externalWaterInput) + call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) + call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) + call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) + call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) + call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) + call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) + endif ! get region cell masks from regionMasks.nc input file call mpas_pool_get_array(regionsPool, 'regionCellMasks', regionCellMasks) @@ -310,6 +363,20 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) allocate(blockSumRegionFaceMeltingFlux(nRegions)) allocate(blockSumRegionGLflux(nRegions)) allocate(blockRegionGLMigrationFlux(nRegions)) + if (config_SGH) then + allocate(blockSumRegionSubglacialWaterVolume(nRegions)) + allocate(blockSumRegionBasalMeltInput(nRegions)) + allocate(blockSumRegionExternalWaterInput(nRegions)) + allocate(blockSumRegionChannelMelt(nRegions)) + allocate(blockSumRegionLakeVolume(nRegions)) + allocate(blockSumRegionLakeArea(nRegions)) + allocate(blockSumRegionGLMeltFlux(nRegions)) + allocate(blockSumRegionTerrestrialMeltFlux(nRegions)) + allocate(blockSumRegionChannelGLMeltFlux(nRegions)) + allocate(blockSumRegionChannelTerrestrialMeltFlux(nRegions)) + allocate(blockSumRegionFlotationFraction(nRegions)) + allocate(regionalSumFlotationFraction(nRegions)) + endif blockSumRegionIceArea = 0.0_RKIND; blockSumRegionIceVolume = 0.0_RKIND blockSumRegionVAF = 0.0_RKIND @@ -324,6 +391,21 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) blockSumRegionFaceMeltingFlux = 0.0_RKIND blockSumRegionGLflux = 0.0_RKIND blockRegionGLMigrationFlux = 0.0_RKIND + + if (config_SGH) then + blockSumRegionSubglacialWaterVolume = 0.0_RKIND + blockSumRegionBasalMeltInput = 0.0_RKIND + blockSumRegionExternalWaterInput = 0.0_RKIND + blockSumRegionChannelMelt = 0.0_RKIND + blockSumRegionLakeVolume = 0.0_RKIND + blockSumRegionLakeArea = 0.0_RKIND + blockSumRegionGLMeltFlux = 0.0_RKIND + blockSumRegionTerrestrialMeltFlux = 0.0_RKIND + blockSumRegionChannelGLMeltFlux = 0.0_RKIND + blockSumRegionChannelTerrestrialMeltFlux = 0.0_RKIND + blockSumRegionFlotationFraction = 0.0_RKIND + regionalSumFlotationFraction = 0.0_RKIND + endif do iCell = 1,nCellsSolve ! loop over cells ! do iGroup = 1,nRegionGroups ! loop over groups @@ -425,8 +507,39 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) real(regionCellMasks(iRegion,iCell),RKIND) * & groundedToFloatingThickness(iCell) * areaCell(iCell) * rhoi / (deltat / scyr) + !! Subglacial Hydrology Calculations + if (config_SGH) then + + ! Subglacial Water Volume + blockSumRegionSubglacialWaterVolume(iRegion) = blockSumRegionSubglacialWaterVolume(iRegion) + & + waterThickness(iCell) * areaCell(iCell) + + ! Basal melt input + blockSumRegionBasalMeltInput(iRegion) = blockSumRegionBasalMeltInput(iRegion) + & + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * basalMeltInput(iCell) * areaCell(iCell) + + ! External water input + blockSumRegionExternalWaterInput(iRegion) = blockSumRegionExternalWaterInput(iRegion) + & + externalWaterInput(iCell) * areaCell(iCell) + + ! Lake Volume + if (waterThickness(iCell) > bedBumpMax) then + blockSumRegionLakeVolume(iRegion) = blockSumRegionLakeVolume(iRegion) + & + (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) + endif + + ! Lake Area + if (waterThickness(iCell) > bedBumpMax) then + blockSumRegionLakeArea(iRegion) = blockSumRegionLakeArea(iRegion) + areaCell(iCell) + endif + + ! Area-weighted flotation fraction for grounded ice + if (li_mask_is_grounded_ice(cellMask(iCell))) then + blockSumRegionFlotationFraction(iRegion) = blockSumRegionFlotationFraction(iRegion) + & + ( waterPressure(iCell) / rhoi / gravity / thickness(iCell) ) * areaCell(iCell) + endif + endif end do ! end loop over regions - ! end do ! end loop over groups end do ! end loop over cells @@ -450,6 +563,29 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) end if ! if edge is on cell in region of interest end do ! end loop over regions end if ! if GL + + if (config_SGH) then + ! Channel Melt + blockSumRegionChannelMelt(iRegion) = blockSumRegionChannelMelt(iRegion) + & + abs(channelMelt(iEdge) * dcEdge(iEdge)) + + ! Meltwater Flux across the grounding line + blockSumRegionGLMeltFlux(iRegion) = blockSumRegionGLMeltFlux(iRegion) + & + abs(hydroMarineMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + + ! Meltwater Flux across terrestrial margins + blockSumRegionTerrestrialMeltFlux(iRegion) = blockSumRegionTerrestrialMeltFlux(iRegion) + & + abs(hydroTerrestrialMarginMask(iEdge) * waterFlux(iEdge) * dvEdge(iEdge) * rho_water) + + ! Meltwater Discharge in channels across grounding line + blockSumRegionChannelGLMeltFlux(iRegion) = blockSumRegionChannelGLMeltFlux(iRegion) + & + abs(hydroMarineMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + + ! Meltwater discharge in channels across terrestrial margin + blockSumRegionChannelTerrestrialMeltFlux(iRegion) = blockSumRegionChannelTerrestrialMeltFlux(iRegion) + & + abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) + endif ! if SGH is on + end do ! end loop over edges block => block % next @@ -494,7 +630,22 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) sums(15) = blockSumRegionVAF(iRegion) sums(16) = blockSumRegionGLflux(iRegion) sums(17) = blockRegionGLMigrationFlux(iRegion) - nVars = 17 + if (config_SGH) then + sums(18) = blockSumRegionSubglacialWaterVolume(iRegion) + sums(19) = blockSumRegionBasalMeltInput(iRegion) + sums(20) = blockSumRegionExternalWaterInput(iRegion) + sums(21) = blockSumRegionChannelMelt(iRegion) + sums(22) = blockSumRegionLakeVolume(iRegion) + sums(23) = blockSumRegionLakeArea(iRegion) + sums(24) = blockSumRegionGLMeltFlux(iRegion) + sums(25) = blockSumRegionTerrestrialMeltFlux(iRegion) + sums(26) = blockSumRegionChannelGLMeltFlux(iRegion) + sums(27) = blockSumRegionChannelTerrestrialMeltFlux(iRegion) + sums(28) = blockSumRegionFlotationFraction(iRegion) + nVars = 28 + else + nVars = 17 + endif call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars)) @@ -526,6 +677,19 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundingLineFlux', regionalSumGroundingLineFlux) call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumGroundingLineMigrationFlux', & regionalSumGroundingLineMigrationFlux) + if (config_SGH) then + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumSubglacialWaterVolume', regionalSumSubglacialWaterVolume) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumBasalMeltInput', regionalSumBasalMeltInput) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumExternalWaterInput', regionalSumExternalWaterInput) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumChannelMelt', regionalSumChannelMelt) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumSubglacialLakeVolume', regionalSumSubglacialLakeVolume) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumSubglacialLakeArea', regionalSumSubglacialLakeArea) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumDistWaterFluxMarineMargin',regionalSumDistWaterFluxMarineMargin) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumDistWaterFluxTerrestrialMargin', regionalSumDistWaterFluxTerrestrialMargin) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumChnlWaterFluxMarineMargin',regionalSumChnlWaterFluxMarineMargin) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalSumChnlWaterFluxTerrestrialMargin', regionalSumChnlWaterFluxTerrestrialMargin) + call mpas_pool_get_array(regionalStatsAMPool, 'regionalAvgFlotationFraction', regionalAvgFlotationFraction) + endif regionalIceArea(iRegion) = reductions(1) regionalIceVolume(iRegion) = reductions(2) @@ -544,6 +708,19 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) regionalVolumeAboveFloatation(iRegion) = reductions(15) regionalSumGroundingLineFlux(iRegion) = reductions(16) regionalSumGroundingLineMigrationFlux(iRegion) = reductions(17) + if (config_SGH) then + regionalSumSubglacialWaterVolume(iRegion) = reductions(18) + regionalSumBasalMeltInput(iRegion) = reductions(19) + regionalSumExternalWaterInput(iRegion) = reductions(20) + regionalSumChannelMelt(iRegion) = reductions(21) + regionalSumSubglacialLakeVolume(iRegion) = reductions(22) + regionalSumSubglacialLakeArea(iRegion) = reductions(23) + regionalSumDistWaterFluxMarineMargin(iRegion) = reductions(24) + regionalSumDistWaterFluxTerrestrialMargin(iRegion) = reductions(25) + regionalSumChnlWaterFluxMarineMargin(iRegion) = reductions(26) + regionalSumChnlWaterFluxTerrestrialMargin(iRegion) = reductions(27) + regionalSumFlotationFraction(iRegion) = reductions(28) + endif if (regionalIceArea(iRegion) > 0.0_RKIND) then regionalIceThicknessMean(iRegion) = regionalIceVolume(iRegion) / regionalIceArea(iRegion) @@ -565,6 +742,15 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) regionalAvgSubshelfMelt(iRegion) = 0.0_RKIND endif + if (config_SGH) then + if (regionalIceArea(iRegion) > 0.0_RKIND) then + ! WHAT SHOULD totalFLoationFraction equivalent be? + regionalAvgFlotationFraction(iRegion) = regionalSumFlotationFraction(iRegion) / regionalIceArea(iRegion) + else + regionalAvgFlotationFraction(iRegion) = 0.0_RKIND + endif + endif + block => block % next end do @@ -624,6 +810,19 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) deallocate(blockSumRegionFaceMeltingFlux) deallocate(blockSumRegionGLflux) deallocate(blockRegionGLMigrationflux) + if (config_SGH) then + deallocate(blockSumRegionSubglacialWaterVolume) + deallocate(blockSumRegionBasalMeltInput) + deallocate(blockSumRegionExternalWaterInput) + deallocate(blockSumRegionChannelMelt) + deallocate(blockSumRegionLakeVolume) + deallocate(blockSumRegionLakeArea) + deallocate(blockSumRegionGLMeltFlux) + deallocate(blockSumRegionTerrestrialMeltFlux) + deallocate(blockSumRegionChannelGLMeltFlux) + deallocate(blockSumRegionChannelTerrestrialMeltFlux) + deallocate(blockSumRegionFlotationFraction) + endif end subroutine li_compute_regional_stats From dd10e47bed3ac329fc89b6188f5f8958fd178e0b Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Wed, 21 Feb 2024 16:53:27 -0700 Subject: [PATCH 047/388] Move reduction of `fluxAcrossGroundingLine` outside SGH condition. The reduction of `fluxAcrossGroundingLine` was accidently moved within a `config_SGH` condition, so that `groundingLineFlux` would only be calculated if `config_SGH` was turned on. Moved the reduction back to where it was to ensure it's calculated in all situations it's needed. --- .../analysis_members/mpas_li_global_stats.F | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F index 2e1d05cbc39..c21b4a2cb86 100755 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F @@ -461,13 +461,14 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) end do ! end loop over cells - if (config_SGH) then - ! Loop over edges - do iEdge = 1, nEdgesSolve + ! Loop over edges + do iEdge = 1, nEdgesSolve + + ! Flux across GL, units = kg/yr + blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) & + * scyr * rhoi ! convert from m^2/s to kg/yr - ! Flux across GL, units = kg/yr - blockGLflux = blockGLflux + fluxAcrossGroundingLine(iEdge) * dvEdge(iEdge) & - * scyr * rhoi ! convert from m^2/s to kg/yr + if (config_SGH) then ! Channel Melt blockSumChannelMelt = blockSumChannelMelt + abs(channelMelt(iEdge) * dcEdge(iEdge)) @@ -484,8 +485,9 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) ! Meltwater discharge in channels across terrestrial margin blockSumChannelTerrestrialMeltFlux = blockSumChannelTerrestrialMeltFlux + abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) - end do ! end loop over edges - endif + endif ! is SGH is turned on + end do ! end loop over edges + block => block % next end do ! end loop over blocks @@ -530,9 +532,9 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) sums(13) = blockSumCalvingFlux sums(14) = blockSumFaceMeltingFlux sums(15) = blockSumVAF + sums(16) = blockGLflux + sums(17) = blockGLMigrationflux if (config_SGH) then - sums(16) = blockGLflux - sums(17) = blockGLMigrationflux sums(18) = blockSumSubglacialWaterVolume sums(19) = blockSumBasalMeltInput sums(20) = blockSumExternalWaterInput @@ -546,7 +548,7 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) sums(28) = blockSumFlotationFraction nVars = 28 else - nVars = 15 + nVars = 17 endif call mpas_dmpar_sum_real_array(dminfo, nVars, sums(1:nVars), reductions(1:nVars)) @@ -574,9 +576,9 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) call mpas_pool_get_array(globalStatsAMPool, 'avgSubshelfMelt', avgSubshelfMelt) call mpas_pool_get_array(globalStatsAMPool, 'totalCalvingFlux', totalCalvingFlux) call mpas_pool_get_array(globalStatsAMPool, 'totalFaceMeltingFlux', totalFaceMeltingFlux) + call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux) + call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux) if (config_SGH) then - call mpas_pool_get_array(globalStatsAMPool, 'groundingLineFlux', groundingLineFlux) - call mpas_pool_get_array(globalStatsAMPool, 'groundingLineMigrationFlux', groundingLineMigrationFlux) call mpas_pool_get_array(globalStatsAMPool, 'totalSubglacialWaterVolume', totalSubglacialWaterVolume) call mpas_pool_get_array(globalStatsAMPool, 'totalBasalMeltInput', totalBasalMeltInput) call mpas_pool_get_array(globalStatsAMPool, 'totalExternalWaterInput', totalExternalWaterInput) @@ -605,9 +607,9 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) totalCalvingFlux = reductions(13) totalFaceMeltingFlux = reductions(14) volumeAboveFloatation = reductions(15) + groundingLineFlux = reductions(16) + groundingLineMigrationFlux = reductions(17) if (config_SGH) then - groundingLineFlux = reductions(16) - groundingLineMigrationFlux = reductions(17) totalSubglacialWaterVolume = reductions(18) totalBasalMeltInput = reductions(19) totalExternalWaterInput = reductions(20) From 6df3ae38c9cbb25897ef9341639c8d7a220ef957 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 22 Feb 2024 08:01:34 -0800 Subject: [PATCH 048/388] fix typo --- components/eam/src/physics/cam/phys_control.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/phys_control.F90 b/components/eam/src/physics/cam/phys_control.F90 index 543fd29753f..b87ea442c4e 100644 --- a/components/eam/src/physics/cam/phys_control.F90 +++ b/components/eam/src/physics/cam/phys_control.F90 @@ -745,7 +745,7 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & if ( present(use_crm_accel_out ) ) use_crm_accel_out = use_crm_accel if ( present(crm_accel_factor_out ) ) crm_accel_factor_out = crm_accel_factor if ( present(crm_accel_uv_out ) ) crm_accel_uv_out = crm_accel_uv - if ( present(MMF_PAM_dyn_per_phys ) ) MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys + if ( present(MMF_PAM_dyn_per_phys_out) ) MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys if ( present(use_subcol_microp_out ) ) use_subcol_microp_out = use_subcol_microp if ( present(macrop_scheme_out ) ) macrop_scheme_out = macrop_scheme From 18147b3b0fa4641e2464575386852cbec5f2302a Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Thu, 22 Feb 2024 15:09:06 -0700 Subject: [PATCH 049/388] Add grounded ice mask to `externalWaterInput` term The grounded ice mask is used in the calculation of the `basalMeltInput` term but was excluded from `externalWaterInput`, which could cause problems in closing budgets. The grounded ice mask was not added to any of the calculations dependent on `waterThickness` b/c SGH model explicitly sets the `waterThickness` to zero outside of the grounded ice area. --- .../src/analysis_members/mpas_li_global_stats.F | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F index c21b4a2cb86..10350fa9d23 100755 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_global_stats.F @@ -440,7 +440,8 @@ subroutine li_compute_global_stats(domain, memberName, timeLevel, err) basalMeltInput(iCell) * areaCell(iCell) ! External water input - blockSumExternalWaterInput = blockSumExternalWaterInput + externalWaterInput(iCell) * areaCell(iCell) + blockSumExternalWaterInput = blockSumExternalWaterInput + & + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * externalWaterInput(iCell) * areaCell(iCell) ! Lake Volume if (waterThickness(iCell) > bedBumpMax) then From 219b5ab9d58ef201dd052b274ee9369e1464b530 Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Thu, 22 Feb 2024 15:17:16 -0700 Subject: [PATCH 050/388] Add missing `regionCellMasks` call from SGH regional stats terms Masking by `regionCellMasks` in SGH regional stats terms was missing, which meant all cell centered SGH values would have been uniform across the regions and match the global stats value. Still not determined how the edge centered SGH value should be mask by region (e.g. using upwind cells region or by the `regionEdgeMasks`), but once that is decided the matching region masking needs to be done for the SGH edge quantities. --- .../analysis_members/mpas_li_regional_stats.F | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F index be9b5c8a255..b93d9ad39c2 100644 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F @@ -512,31 +512,37 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) ! Subglacial Water Volume blockSumRegionSubglacialWaterVolume(iRegion) = blockSumRegionSubglacialWaterVolume(iRegion) + & - waterThickness(iCell) * areaCell(iCell) - - ! Basal melt input - blockSumRegionBasalMeltInput(iRegion) = blockSumRegionBasalMeltInput(iRegion) + & - real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * basalMeltInput(iCell) * areaCell(iCell) + (real(regionCellMasks(iRegion,iCell),RKIND) * waterThickness(iCell) * areaCell(iCell)) + + if (li_mask_is_grounded_ice(cellMask(iCell))) then + ! Basal melt input + blockSumRegionBasalMeltInput(iRegion) = blockSumRegionBasalMeltInput(iRegion) + & + (real(regionCellMasks(iRegion,iCell),RKIND) * basalMeltInput(iCell) * areaCell(iCell)) + endif ! External water input blockSumRegionExternalWaterInput(iRegion) = blockSumRegionExternalWaterInput(iRegion) + & - externalWaterInput(iCell) * areaCell(iCell) + (real(regionCellMasks(iRegion,iCell),RKIND) * & + real(li_mask_is_grounded_ice_int(cellMask(iCell)),RKIND) * & + externalWaterInput(iCell) * areaCell(iCell)) ! Lake Volume if (waterThickness(iCell) > bedBumpMax) then blockSumRegionLakeVolume(iRegion) = blockSumRegionLakeVolume(iRegion) + & - (waterThickness(iCell) - bedBumpMax) * areaCell(iCell) + (real(regionCellMasks(iRegion,iCell),RKIND) * (waterThickness(iCell) - bedBumpMax) * areaCell(iCell)) endif ! Lake Area if (waterThickness(iCell) > bedBumpMax) then - blockSumRegionLakeArea(iRegion) = blockSumRegionLakeArea(iRegion) + areaCell(iCell) + blockSumRegionLakeArea(iRegion) = blockSumRegionLakeArea(iRegion) + & + (real(regionCellMasks(iRegion,iCell),RKIND) * areaCell(iCell)) endif ! Area-weighted flotation fraction for grounded ice if (li_mask_is_grounded_ice(cellMask(iCell))) then blockSumRegionFlotationFraction(iRegion) = blockSumRegionFlotationFraction(iRegion) + & - ( waterPressure(iCell) / rhoi / gravity / thickness(iCell) ) * areaCell(iCell) + (real(regionCellMasks(iRegion,iCell),RKIND) * & + ( waterPressure(iCell) / rhoi / gravity / thickness(iCell) ) * areaCell(iCell)) endif endif end do ! end loop over regions @@ -564,6 +570,12 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) end do ! end loop over regions end if ! if GL + ! TO DO: Need to define our own condition on how to decide which region to put the edge quantities + ! TO DO: Make sure SGH terms are masked based on region (using regionEdgeMasks?) b/c calculations are + ! currently unmasked and therefore global values + + + ! assign the SGH stats this edge quantities to the region of the upwind cell if (config_SGH) then ! Channel Melt blockSumRegionChannelMelt(iRegion) = blockSumRegionChannelMelt(iRegion) + & @@ -584,8 +596,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) ! Meltwater discharge in channels across terrestrial margin blockSumRegionChannelTerrestrialMeltFlux(iRegion) = blockSumRegionChannelTerrestrialMeltFlux(iRegion) + & abs( hydroTerrestrialMarginMask(iEdge) * channelDischarge(iEdge) * rho_water) - endif ! if SGH is on - + endif ! if SGH is on end do ! end loop over edges block => block % next From fae4e15379b7650f1c2d497b7d6f9119be89f90c Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Thu, 22 Feb 2024 15:27:29 -0700 Subject: [PATCH 051/388] Deallocate `regionalSumFlotationFraction`. Was missing the deallocation of `regionalSumFlotationFraction`, which is a local variable needed for calculating the numerator of `regionalAvgFlotationFraction`. --- .../src/analysis_members/mpas_li_regional_stats.F | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F index b93d9ad39c2..912eca2a502 100644 --- a/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F +++ b/components/mpas-albany-landice/src/analysis_members/mpas_li_regional_stats.F @@ -270,7 +270,7 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) real (kind=RKIND), dimension(:), allocatable :: blockSumRegionChannelGLMeltFlux real (kind=RKIND), dimension(:), allocatable :: blockSumRegionChannelTerrestrialMeltFlux real (kind=RKIND), dimension(:), allocatable :: blockSumRegionFlotationFraction - ! local variable needed calculating average floation fraction in a region + ! local variable needed calculating numerator of regionalAvgFlotationFraction real (kind=RKIND), dimension(:), allocatable:: regionalSumFlotationFraction ! local variables @@ -833,6 +833,8 @@ subroutine li_compute_regional_stats(domain, memberName, timeLevel, err) deallocate(blockSumRegionChannelGLMeltFlux) deallocate(blockSumRegionChannelTerrestrialMeltFlux) deallocate(blockSumRegionFlotationFraction) + ! local variable needed for calculating numerator of regionalAvgFlotationFraction + deallocate(regionalSumFlotationFraction) endif end subroutine li_compute_regional_stats From abaa6cae48047fb4d4759fbd8d25d66f096c0a18 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 19:34:45 -0700 Subject: [PATCH 052/388] Add missing error flag so model actually dies when error occurs --- .../mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F | 1 + 1 file changed, 1 insertion(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index aacfbed95ad..f1cc7aceed2 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1080,6 +1080,7 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) else call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) + err = ior(err, 1) endif endif From 6bb3000ce6caa7769555b4f20bc6130f60d2fe1e Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 19:59:03 -0700 Subject: [PATCH 053/388] Allow restarts at any interval when using SLM This commit changes how restarts are handled when the SLM is active to allow MALI to be restarted at any arbitrary restart interval and have the SLM restart correctly. This is done by changing the SLM coupling alarm to be based off of the original simulationStartTime (instead of the start time of the current execution). This required moving the creation of the coupling alarm to later in initialization so that the variable simulationStartTime is available. With this change, it was also necessary to change the way the SLM time level is calculated on a restart to take the floor of the elapsed time divided by the coupling interval, rather than requiring that there be no remainder. This adds a little fragility because there is no way to double check that is the correct SLM time level, but if this is set up correctly, it should be handled properly. Finally, as part of these changes, I also removed the check on init that the coupling interval divides evenly into the restart interval, because that's no longer a requirement. That's sort of too bad, because it was a lot of work to figure out how to make that check! But it's nicer to not have that restriction. --- .../src/mode_forward/mpas_li_bedtopo.F | 69 +++++++++---------- .../src/mode_forward/mpas_li_core.F | 17 ----- 2 files changed, 32 insertions(+), 54 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index f1cc7aceed2..4ead2074546 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -407,6 +407,10 @@ subroutine slmodel_init(domain, err) integer :: itersl, dtime ! SLM variable real :: starttime ! SLM variable integer, dimension(:), pointer :: cellMask ! integer bitmask for cells + integer, pointer :: config_slm_coupling_interval + type (MPAS_TimeInterval_type) :: slm_coupling_interval + character (len=StrKIND), pointer :: simulationStartTime + type (MPAS_Time_type) :: simulationStartTime_timeType ! MPI variables integer, dimension(:), pointer :: indexToCellID @@ -415,12 +419,30 @@ subroutine slmodel_init(domain, err) err = 0 err_tmp = 0 + + call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) + + ! Set up the alarm for the coupling time interval + call mpas_pool_get_config(liConfigs, 'config_slm_coupling_interval', config_slm_coupling_interval) + call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) + err = ior(err,err_tmp) + call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) + call mpas_set_time(simulationStartTime_timeType, dateTimeString=simulationStartTime, ierr=err_tmp) + err = ior(err,err_tmp) + call mpas_add_clock_alarm(domain%clock, 'slmCouplingInterval', alarmTime=simulationStartTime_timeType, & + alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) + err = ior(err,err_tmp) + if (mpas_is_alarm_ringing(domain%clock, 'slmCouplingInterval', ierr=err_tmp)) then + err = ior(err, err_tmp) + call mpas_reset_clock_alarm(domain%clock, 'slmCouplingInterval', ierr=err_tmp) + err = ior(err, err_tmp) + endif + ! initialize interpolation call interpolate_init(domain, err_tmp) err = ior(err, err_tmp) ! Set needed variables for using MPI - call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) call mpas_pool_get_dimension(meshPool, 'nCells', nCellsAll) call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsOwned) call mpas_pool_get_array(meshPool, 'indexToCellID', indexToCellID) @@ -448,7 +470,7 @@ subroutine slmodel_init(domain, err) call sl_drive_readnl(itersl, dtime, starttime) !SLM subroutine ! First, check consistency in coupling interval set up in MALI and SLM - call check_SLM_coupling_interval(dtime, meshPool, domain % streamManager, err_tmp) + call check_SLM_coupling_interval(dtime, meshPool, err_tmp) err = ior(err, err_tmp) if (err /= 0) then call mpas_log_write("Error occurred in check_SLM_coupling_interval.", MPAS_LOG_ERR) @@ -985,7 +1007,7 @@ end subroutine check ! !----------------------------------------------------------------------- - subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) + subroutine check_SLM_coupling_interval(slm_dt1, meshPool, err) use mpas_timekeeping use mpas_stream_manager @@ -993,18 +1015,16 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) integer, intent (in) :: slm_dt1 type (mpas_pool_type), intent(in) :: meshPool !< mesh information - type (MPAS_streamManager_type), intent(inout) :: streamManager integer, intent(out) :: err ! local variables integer, pointer :: config_slm_coupling_interval logical, pointer :: config_adaptive_timestep character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval, config_dt - type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, restart_interval, zero_interval + type (MPAS_TimeInterval_Type) :: coupling_interval, force_interval, dt_interval, zero_interval type (MPAS_Time_Type) :: start_time character (len=StrKIND), pointer :: simulationStartTime integer :: YYYY, MM, DD, H, M, S ! time components - type (MPAS_stream_list_type), pointer :: stream_cursor integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder integer :: err_tmp @@ -1066,26 +1086,9 @@ subroutine check_SLM_coupling_interval(slm_dt1, meshPool, streamManager, err) endif endif - ! Now check that restart interval is an even multiple of coupling interval - stream_cursor => streamManager % streams % head - do while (associated(stream_cursor)) - if ( trim(stream_cursor % name) == 'restart' .and. (stream_cursor % active_stream) ) then - call mpas_log_write("Checking restart interval against SLM coulping interval") - restart_interval = MPAS_stream_mgr_get_stream_interval(streamManager, 'restart', MPAS_STREAM_OUTPUT, ierr=err_tmp) - err = ior(err, err_tmp) - call mpas_interval_division(start_time, restart_interval, coupling_interval, n_intervals, remainder) - if (remainder .EQ. zero_interval) then - call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & - "with no remainder - check passes", intArgs=(/int(n_intervals)/)) - else - call mpas_log_write("config_slm_coupling_interval divides into restart interval $i times " // & - "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) - endif - endif + ! No need to compare restart interval and coupling interval because restarts with SLM are supported for + ! any restart interval now - stream_cursor => stream_cursor % next - enddo call mpas_log_write("") !-------------------------------------------------------------------- @@ -1118,7 +1121,7 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) ! local vars integer, pointer :: config_slm_coupling_interval character (len=StrKIND), pointer :: xtime, simulationStartTime - type (MPAS_TimeInterval_Type) :: coupling_interval, zero_interval + type (MPAS_TimeInterval_Type) :: coupling_interval type (MPAS_Time_Type) :: start_time, curr_time integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder @@ -1141,17 +1144,9 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) err = ior(err, err_tmp) call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) - call mpas_set_timeInterval(zero_interval, dt = 0.0_RKIND) - if (remainder .EQ. zero_interval) then - call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & - "with no remainder - check passes", intArgs=(/int(n_intervals)/)) - slmTimeStep = int(n_intervals) - else - call mpas_log_write("SLM Restart check: config_slm_coupling_interval divides into elapsed time $i times " // & - "with nonzero remainder", MPAS_LOG_ERR, intArgs=(/int(n_intervals)/)) - err = ior(err, 1) - slmTimeStep = -999 - endif + slmTimeStep = int(n_intervals) + call mpas_log_write("SLM Restart check: Using SLM time level $i because config_slm_coupling_interval divides into " // & + "elapsed time that many times ", intArgs=(/int(slmTimeStep)/)) call mpas_log_write("") !-------------------------------------------------------------------- diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F index 146b4e36d80..16c7c780720 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_core.F @@ -1105,13 +1105,11 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) type (MPAS_Time_Type) :: startTime, stopTime, alarmStartTime type (MPAS_TimeInterval_type) :: runDuration, timeStep, alarmTimeStep type (MPAS_TimeInterval_type) :: adaptDtForceInterval - type (MPAS_TimeInterval_type) :: slm_coupling_interval character (len=StrKIND), pointer :: config_start_time, config_run_duration, config_stop_time, & config_output_interval, config_restart_interval ! MPAS standard configs character (len=StrKIND), pointer :: config_dt ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_adaptive_timestep_force_interval ! MPAS LI-specific config option character (len=StrKIND), pointer :: config_restart_timestamp_name - character (len=StrKIND), pointer :: config_uplift_method integer, pointer :: config_slm_coupling_interval character (len=StrKIND) :: restartTimeStamp !< string to be read from file integer, pointer :: config_year_digits @@ -1131,7 +1129,6 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) call mpas_pool_get_config(configs, 'config_stop_time', config_stop_time) call mpas_pool_get_config(configs, 'config_restart_timestamp_name', config_restart_timestamp_name) call mpas_pool_get_config(configs, 'config_adaptive_timestep_force_interval', config_adaptive_timestep_force_interval) - call mpas_pool_get_config(configs, 'config_uplift_method', config_uplift_method) call mpas_pool_get_config(configs, 'config_slm_coupling_interval', config_slm_coupling_interval) @@ -1196,20 +1193,6 @@ subroutine li_simulation_clock_init(core_clock, configs, ierr) endif ierr = ior(ierr, err_tmp) - ! Set up the coupling time interval if MALI is coupled to sea-level model - if (trim(config_uplift_method) == "sealevelmodel") then - call mpas_set_timeInterval(slm_coupling_interval, YY=config_slm_coupling_interval, ierr=err_tmp) - ierr = ior(ierr,err_tmp) - call mpas_add_clock_alarm(core_clock, 'slmCouplingInterval', alarmTime=startTime, & - alarmTimeInterval=slm_coupling_interval, ierr=err_tmp) - ierr = ior(ierr,err_tmp) - if (mpas_is_alarm_ringing(core_clock, 'slmCouplingInterval', ierr=err_tmp)) then - ierr = ior(ierr, err_tmp) - call mpas_reset_clock_alarm(core_clock, 'slmCouplingInterval', ierr=err_tmp) - ierr = ior(ierr, err_tmp) - endif - endif - ! === error check if (ierr /= 0) then call mpas_log_write("An error has occurred in li_simulation_clock_init.", MPAS_LOG_ERR) From be5f341ce4d50beb4393df4f1dc386b4e6fb59df Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 20:17:19 -0700 Subject: [PATCH 054/388] Add addl info on restart about the calculated time since last SLM call This doesn't serve any internal purpose, but it could help a user detect an error in their configuration. --- .../src/mode_forward/mpas_li_bedtopo.F | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index 4ead2074546..b3461a52ae4 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -1125,6 +1125,7 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) type (MPAS_Time_Type) :: start_time, curr_time integer (kind=I8KIND) :: n_intervals type (MPAS_TimeInterval_type) :: remainder + character (len=StrKIND) :: remainder_string integer :: err_tmp err = 0 @@ -1135,7 +1136,6 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) call mpas_set_timeInterval(coupling_interval, YY=config_slm_coupling_interval, MM=0, DD=0, H=0, M=0, S=0, ierr=err_tmp) err = ior(err, err_tmp) - call mpas_pool_get_array(meshPool, 'simulationStartTime', simulationStartTime) call mpas_pool_get_array(meshPool, 'xtime', xtime) call mpas_set_time(start_time, dateTimeString=simulationStartTime, ierr=err_tmp) @@ -1145,8 +1145,12 @@ subroutine find_slm_restart_timestep(meshPool, slmTimeStep, err) call mpas_interval_division(start_time, curr_time - start_time, coupling_interval, n_intervals, remainder) slmTimeStep = int(n_intervals) - call mpas_log_write("SLM Restart check: Using SLM time level $i because config_slm_coupling_interval divides into " // & + call mpas_get_timeInterval(remainder, start_time, timeString=remainder_string, ierr=err_tmp) + err = ior(err, err_tmp) + call mpas_log_write("SLM Restart: Using SLM time level $i because config_slm_coupling_interval divides into " // & "elapsed time that many times ", intArgs=(/int(slmTimeStep)/)) + call mpas_log_write(" That calculation implies it has been " // trim(remainder_string) // " since last SLM coupling. " // & + "If that interval seems wrong, there may be an error in your configuration.") call mpas_log_write("") !-------------------------------------------------------------------- From 052b15de927db57d213bdc8e4eeba57237e9a8e6 Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Fri, 23 Feb 2024 20:46:11 -0700 Subject: [PATCH 055/388] Don't call SLM on init of a restart It's not needed, and if the restart time is not a coupling interval, it will make the SLM get out of sync. --- .../src/mode_forward/mpas_li_bedtopo.F | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index b3461a52ae4..d5aaf12672b 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -501,10 +501,13 @@ subroutine slmodel_init(domain, err) call find_slm_restart_timestep(meshPool, slmTimeStep, err_tmp) err = ior(err, err_tmp) - if (err == 0) then - call mpas_log_write("Calling the SLM. SLM timestep $i", intArgs=(/slmTimeStep/)) - call slmodel_solve(slmTimeStep, domain) - endif + + ! Note: no need to call slmodel_solve on init of a restart. + ! If this time level happens to be a coupling interval, SLM would have been solved already + ! in the previous run that generated the restart file. + ! While it would not hurt (other than unneeded execution time) to call SLM again if the + ! restart time level happens to be a coupling interval, if the restart time is in between + ! coupling intervals calling SLM here will make things out of sync. else From 8b89b6fc87e9a0dbbd272d786e18f550b314a151 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 26 Feb 2024 16:05:17 -0800 Subject: [PATCH 056/388] adjust default MMF2 configuration --- components/eam/cime_config/config_component.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/eam/cime_config/config_component.xml b/components/eam/cime_config/config_component.xml index c7585072ac9..16ff080ae83 100755 --- a/components/eam/cime_config/config_component.xml +++ b/components/eam/cime_config/config_component.xml @@ -75,10 +75,11 @@ -crm pam -pam_dycor spam -crm_dt 8 -crm pam -pam_dycor awfl -crm_dt 8 -use_MMF -nlev 60 -crm_nz 50 - -crm_dx 2000 -crm_nx 64 -crm_ny 1 + -crm_dx 2000 -crm_nx 64 -crm_ny 1 -crm_nx_rad 4 -crm_ny_rad 1 + -crm_dx 2000 -crm_nx 45 -crm_ny 1 -crm_nx_rad 5 -crm_ny_rad 1 -MMF_microphysics_scheme sam1mom -chem none -MMF_microphysics_scheme p3 -chem none - -crm_nx_rad 4 -crm_ny_rad 1 -rad rrtmgp -rrtmgpxx + -rad rrtmgp -rrtmgpxx -use_MMF_VT -use_MMF_ESMT -aquaplanet From ef9d3281c9051dadc2627f6abcf9d4e0308647bd Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 27 Feb 2024 08:18:08 -0800 Subject: [PATCH 057/388] add PAM coupler options to override SPAM parameter defaults --- components/eam/src/physics/crm/pam/pam_driver.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index 128974a856e..c325945f880 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -54,6 +54,14 @@ extern "C" void pam_driver() { coupler.set_option("sponge_time_scale",60); // minimum damping timescale at top coupler.set_option("crm_acceleration_ceaseflag",false); //------------------------------------------------------------------------------------------------ + // coupler options for SPAM dycor + coupler.set_option("spam_couple_wind_exact_inverse",true); + coupler.set_option("spam_clip_negative_densities",true); + coupler.set_option("spam_clip_vertical_velocities",true); + coupler.set_option("spam_adjust_crm_per_phys_using_vert_cfl",true); + coupler.set_option("spam_target_cfl",0.7); + coupler.set_option("spam_max_w",50.0); + //------------------------------------------------------------------------------------------------ // Allocate the coupler state and retrieve host/device data managers coupler.allocate_coupler_state( crm_nz , crm_ny , crm_nx , nens ); From 644bf4c00c6dc3295fc3996455318e0fdd6f9c51 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 27 Feb 2024 08:24:59 -0800 Subject: [PATCH 058/388] update pam_state_recall_dry_density --- .../eam/src/physics/crm/pam/pam_state.h | 54 +++++++++++-------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index 34cc42a4a78..3266899ba21 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -258,6 +258,13 @@ inline void pam_state_save_dry_density( pam::PamCoupler &coupler ) { // recall CRM dry density saved previously - only for anelastic case +// Note - The need for this arises because the SPAM dycor diagnoses the dry +// density in a way that preserves the total density to match the reference +// density. However, this is problematic in the presence of the GCM forcing +// which naturally changes the total density. Therefore, we can recall the +// previous dry density and use it to replace the horizontal mean returned from +// the dycor, which ensures that the impact of GCM forcing is preserved while +// also retaining the dry density perturbations created by the dycor. inline void pam_state_recall_dry_density( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; @@ -270,29 +277,30 @@ inline void pam_state_recall_dry_density( pam::PamCoupler &coupler ) { auto crm_rho_d = dm_device.get("density_dry"); auto tmp_rho_d = dm_device.get("density_dry_save"); //------------------------------------------------------------------------------------------------ - #ifdef MMF_ALT_DENSITY_RECALL - // initialize horizontal mean of previous CRM dry density - real2d old_hmean_rho_d("old_hmean_rho_d" ,nz,nens); - real2d new_hmean_rho_d("new_hmean_rho_d" ,nz,nens); - parallel_for(SimpleBounds<2>(nz,nens), YAKL_LAMBDA (int k, int iens) { - old_hmean_rho_d(k,iens) = 0; - new_hmean_rho_d(k,iens) = 0; - }); - real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions - // calculate horizontal mean of previous CRM dry density - parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { - atomicAdd( old_hmean_rho_d(k,iens), tmp_rho_d(k,j,i,iens) * r_nx_ny ); - atomicAdd( new_hmean_rho_d(k,iens), crm_rho_d(k,j,i,iens) * r_nx_ny ); - }); - // replace horizontal mean dry density with prevoius value - parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { - crm_rho_d(k,j,i,iens) = crm_rho_d(k,j,i,iens) - new_hmean_rho_d(k,iens) + old_hmean_rho_d(k,iens); - }); - #else - parallel_for( "Recall CRM dry density",SimpleBounds<4>(nz,ny,nx,nens),YAKL_LAMBDA (int k_crm, int j, int i, int iens) { - crm_rho_d(k_crm,j,i,iens) = tmp_rho_d(k_crm,j,i,iens); - }); - #endif + // initialize horizontal mean of previous CRM dry density + real2d old_hmean_rho_d("old_hmean_rho_d" ,nz,nens); + real2d new_hmean_rho_d("new_hmean_rho_d" ,nz,nens); + parallel_for(SimpleBounds<2>(nz,nens), YAKL_LAMBDA (int k, int iens) { + old_hmean_rho_d(k,iens) = 0; + new_hmean_rho_d(k,iens) = 0; + }); + real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions + // calculate horizontal mean of previous CRM dry density + parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { + atomicAdd( old_hmean_rho_d(k,iens), tmp_rho_d(k,j,i,iens) * r_nx_ny ); + atomicAdd( new_hmean_rho_d(k,iens), crm_rho_d(k,j,i,iens) * r_nx_ny ); + }); + // replace horizontal mean dry density with previous value + parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { + crm_rho_d(k,j,i,iens) = crm_rho_d(k,j,i,iens) - new_hmean_rho_d(k,iens) + old_hmean_rho_d(k,iens); + }); + //------------------------------------------------------------------------------------------------ + // Original simple appraoch to completely reinstate the previous dry density field + // (this was shown to negatively impact the model stability) + // This was used initially, but the above + // parallel_for( "Recall CRM dry density",SimpleBounds<4>(nz,ny,nx,nens),YAKL_LAMBDA (int k_crm, int j, int i, int iens) { + // crm_rho_d(k_crm,j,i,iens) = tmp_rho_d(k_crm,j,i,iens); + // }); //------------------------------------------------------------------------------------------------ } From 6b7dcbeae6ac486a59041eb78e882ae06e1a8ea0 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 27 Feb 2024 08:37:57 -0800 Subject: [PATCH 059/388] update PAM submodule --- components/eam/src/physics/crm/pam/external | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/external b/components/eam/src/physics/crm/pam/external index 87731d56aee..9d692dccdd6 160000 --- a/components/eam/src/physics/crm/pam/external +++ b/components/eam/src/physics/crm/pam/external @@ -1 +1 @@ -Subproject commit 87731d56aeee4bfae4750e17732828ba186367a7 +Subproject commit 9d692dccdd67d9c4dc278c76290504a2af8cd187 From 40a442cbb3a3a5ab4cf1c570be56dadaed2d66ea Mon Sep 17 00:00:00 2001 From: Andrew Nolan Date: Tue, 5 Mar 2024 08:47:11 -0800 Subject: [PATCH 060/388] Use `regionEdgeMask` to calculate SGH regional stats defined on edges. Addes `regionEdgeMask` and `regionVertexMask` to the registry so the additional mask variables can be included in the `regionsInput` stream. --- .../mpas-albany-landice/src/Registry.xml | 10 +++- .../analysis_members/mpas_li_regional_stats.F | 58 +++++++++++-------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry.xml b/components/mpas-albany-landice/src/Registry.xml index a1ddaf74401..4fc54d8c239 100644 --- a/components/mpas-albany-landice/src/Registry.xml +++ b/components/mpas-albany-landice/src/Registry.xml @@ -1,4 +1,4 @@ - +/?xml version="1.0"?> @@ -936,6 +936,8 @@ input_interval="initial_only" runtime_format="single_file"> + + @@ -937,10 +938,9 @@ runtime_format="single_file"> - 3x3min @@ -176,6 +177,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 0.5x0.5 0.5x0.5 5x5min +0.1x0.1 + mksrf_flakwat @@ -203,6 +206,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). mksrf_fslp10 mksrf_fero mksrf_ffert +mksrf_ftoprad lnd/clm2/rawdata/mksrf_navyoro_20min.c010129.nc @@ -313,6 +317,9 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/rawdata/mksrf_fert.c220309.nc +lnd/clm2/rawdata/mksrf_toprad_0.1x0.1.c231218.nc + diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 8182c6d9066..10a9f98ee8e 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -772,7 +772,7 @@ in its attributes. (Only used if scripgriddata_src_type = UGRID.) + valid_values="mksrf_fsoitex,mksrf_forganic,mksrf_flakwat,mksrf_fwetlnd,mksrf_fmax,mksrf_fmax,mksrf_fglacier,mksrf_fvocef,mksrf_furbtopo,mksrf_flndtopo,firrig,mksrf_furban,mksrf_fvegtyp,mksrf_fsoicol,mksrf_fsoiord,mksrf_flai,mksrf_fgdp,mksrf_fpeat,mksrf_fabm,mksrf_ftopostats,mksrf_fvic,mksrf_fch4,mksrf_fgrvl,mksrf_fslp10,mksrf_fero,mksrf_ffert,mksrf_ftoprad" > Filename for mksurfdata_map to remap raw data into the output surface dataset @@ -931,10 +931,15 @@ ELM-Erosion parameters dataset + input_pathname="abs" group="elmexp" valid_values="" > ELM-Fertilizer dataset + +Topography parameters dataset for TOP solar radiation parameterization + + If TRUE, output variables in double precision for mksurfdata diff --git a/components/elm/tools/mksurfdata_map/mksurfdata.pl b/components/elm/tools/mksurfdata_map/mksurfdata.pl index 222a9c51bd1..05389d0d579 100755 --- a/components/elm/tools/mksurfdata_map/mksurfdata.pl +++ b/components/elm/tools/mksurfdata_map/mksurfdata.pl @@ -421,8 +421,8 @@ ($) my $mkopts = "-csmdata $CSMDATA -silent -justvalue -namelist elmexp $usrnam"; foreach my $typ ( "lak", "veg", "voc", "top", "tex", "col","ord", "fmx", "lai", "urb", "org", "glc", "utp", "wet", - "gdp", "peat","abm", "topostats" , "vic", "ch4", - "pho", "grvl", "slp10", "ero", "fert") { + "gdp", "peat","abm", "topostats" , "vic", "ch4", + "pho", "grvl", "slp10", "ero", "fert", "toprad") { my $lmask = `$scrdir/../../bld/queryDefaultNamelist.pl $mopts -silent -options type=$typ,mergeGIS=$merge_gis,hirespft=$hirespft -var lmask`; $lmask = trim($lmask); my $hgrid = `$scrdir/../../bld/queryDefaultNamelist.pl $mopts -options type=$typ,hirespft=$hirespft -var hgrid`; @@ -539,6 +539,7 @@ ($) map_fslp10 = '$map{'slp10'}' map_fero = '$map{'ero'}' map_ffert = '$map{'fert'}' + map_ftoprad = '$map{'toprad'}' mksrf_fsoitex = '$datfil{'tex'}' mksrf_forganic = '$datfil{'org'}' mksrf_flakwat = '$datfil{'lak'}' @@ -563,6 +564,7 @@ ($) mksrf_fslp10 = '$datfil{'slp10'}' mksrf_fero = '$datfil{'ero'}' mksrf_ffert = '$datfil{'fert'}' + mksrf_ftoprad = '$datfil{'toprad'}' EOF my $urbdesc = "urb3den"; my $rcp_option= ""; diff --git a/components/elm/tools/mksurfdata_map/src/Srcfiles b/components/elm/tools/mksurfdata_map/src/Srcfiles index f8bda5dcf61..96cec841a94 100644 --- a/components/elm/tools/mksurfdata_map/src/Srcfiles +++ b/components/elm/tools/mksurfdata_map/src/Srcfiles @@ -28,6 +28,7 @@ mkVICparamsMod.F90 mkCH4inversionMod.F90 mkSedMod.F90 mkFertMod.F90 +mktopradMod.F90 nanMod.F90 shr_file_mod.F90 shr_sys_mod.F90 diff --git a/components/elm/tools/mksurfdata_map/src/mkfileMod.F90 b/components/elm/tools/mksurfdata_map/src/mkfileMod.F90 index c3f67cc7a12..50b029efc7d 100644 --- a/components/elm/tools/mksurfdata_map/src/mkfileMod.F90 +++ b/components/elm/tools/mksurfdata_map/src/mkfileMod.F90 @@ -15,6 +15,7 @@ subroutine mkfile(domain, fname, dynlanduse) use mkpftMod , only : mkpftAtt use mksoilMod , only : mksoilAtt use mkSedMod , only : mksedAtt + use mktopradMod , only : mktopradAtt use mkharvestMod , only : mkharvest_fieldname, mkharvest_numtypes, mkharvest_longname use mkncdio , only : check_ret, ncd_defvar use mkdomainMod @@ -297,6 +298,10 @@ subroutine mkfile(domain, fname, dynlanduse) call check_ret(nf_put_att_text(ncid, NF_GLOBAL, & 'map_fertilizer_file', len_trim(str), trim(str)), subname) + str = get_filename(map_ftoprad) + call check_ret(nf_put_att_text(ncid, NF_GLOBAL, & + 'map_ftoprad_file', len_trim(str), trim(str)), subname) + ! ---------------------------------------------------------------------- ! Define variables ! ---------------------------------------------------------------------- @@ -313,6 +318,8 @@ subroutine mkfile(domain, fname, dynlanduse) call mksedAtt( ncid, dynlanduse, xtype ) + call mktopradAtt( ncid, dynlanduse, xtype ) + if (outnc_1d) then call ncd_defvar(ncid=ncid, varname='AREA' , xtype=nf_double, & dim1name='gridcell',& diff --git a/components/elm/tools/mksurfdata_map/src/mksurfdat.F90 b/components/elm/tools/mksurfdata_map/src/mksurfdat.F90 index d062907cdcc..a936c43052b 100644 --- a/components/elm/tools/mksurfdata_map/src/mksurfdat.F90 +++ b/components/elm/tools/mksurfdata_map/src/mksurfdat.F90 @@ -44,7 +44,9 @@ program mksurfdat use mkCH4inversionMod , only : mkCH4inversion use mksoilphosphorusMod, only : mksoilphosphorus use mkSedMod , only : mkgrvl, mkslp10, mkEROparams - use mkFertMod , only : mkfert! + use mkFertMod , only : mkfert + use mktopradMod , only : mktoprad +! ! !ARGUMENTS: implicit none @@ -152,6 +154,10 @@ program mksurfdat real(r8), allocatable :: litho(:) ! lithology erodiblity index (unitless) real(r8), allocatable :: nfert(:,:) ! crop nitrogen fertilizer (g/m^2) real(r8), allocatable :: pfert(:,:) ! crop phosphorus fertilizer (g/m^2) + real(r8), allocatable :: sinsl_sinas(:) ! sin(slope)*sin(aspect) / cos(slope) + real(r8), allocatable :: sinsl_cosas(:) ! sin(slope)*cos(aspect) / cos(slope) + real(r8), allocatable :: sky_view(:) ! mean of (sky view factor / cos(slope)) + real(r8), allocatable :: terrain_config(:) ! mean of (terrain configuration factor / cos(slope)) type(domain_type) :: ldomain @@ -187,6 +193,7 @@ program mksurfdat mksrf_fslp10, & mksrf_fero, & mksrf_ffert, & + mksrf_ftoprad, & nglcec, & numpft, & soil_color, & @@ -224,6 +231,7 @@ program mksurfdat map_fslp10, & map_ffert, & map_fero, & + map_ftoprad, & outnc_large_files, & outnc_double, & outnc_dims, & @@ -264,8 +272,9 @@ program mksurfdat ! mksrf_fphosphorus Soil phosphorus dataset ! mksrf_fgrvl ---- Soil gravel content dataset ! mksrf_fslp10 --- Slope percentile dataset - ! mksrf_fero ----- ELM-Erosion parameters dataset + ! mksrf_fero ----- ELM-Erosion parameters dataset ! mksrf_ffert ---- Crop Fertilizer dataset + ! mksrf_ftoprad --- TOP parameters dataset for solar radiation parameterization ! ====================================== ! Must specify mapping file for the different datafiles above ! ====================================== @@ -295,6 +304,7 @@ program mksurfdat ! map_fslp10 ------ Mapping for mksrf_fslp10 ! map_fero -------- Mapping for mksrf_fero ! map_ffert ------- Mapping for mksrf_ffert + ! map_ftoprad_______ Mapping for mksrf_ftoprad ! ====================================== ! Optionally specify setting for: ! ====================================== @@ -464,7 +474,11 @@ program mksurfdat tillage(ns_o) , & litho(ns_o) , & nfert(ns_o,0:numpft) , & - pfert(ns_o,0:numpft) ) + pfert(ns_o,0:numpft) , & + sinsl_sinas(ns_o) , & + sinsl_cosas(ns_o) , & + sky_view(ns_o) , & + terrain_config(ns_o) ) landfrac_pft(:) = spval pctlnd_pft(:) = spval @@ -511,6 +525,10 @@ program mksurfdat litho(:) = spval nfert(:,:) = 0._r8 pfert(:,:) = 0._r8 + sinsl_sinas(:) = spval + sinsl_cosas(:) = spval + sky_view(:) = spval + terrain_config(:) = spval ! ---------------------------------------------------------------------- ! Open diagnostic output log file @@ -581,6 +599,7 @@ program mksurfdat write(ndiag,*)' mapping for slope percentile ',trim(map_fslp10) write(ndiag,*)' mapping for erosion params ',trim(map_fero) write(ndiag,*)' mapping for fertilizer ',trim(map_ffert) + write(ndiag,*)' mapping for TOP params ',trim(map_ftoprad) if (mksrf_fdynuse /= ' ') then write(6,*)'mksrf_fdynuse = ',trim(mksrf_fdynuse) @@ -768,6 +787,12 @@ program mksurfdat nfert_o=nfert, pfert_o=pfert) end if + call mktoprad(ldomain, mapfname=map_ftoprad, datfname=mksrf_ftoprad, varname = 'SINSL_SINAS', ndiag=ndiag, top_o=sinsl_sinas, nodata=0.0_r8) + call mktoprad(ldomain, mapfname=map_ftoprad, datfname=mksrf_ftoprad, varname = 'SINSL_COSAS', ndiag=ndiag, top_o=sinsl_cosas, nodata=0.0_r8) + call mktoprad(ldomain, mapfname=map_ftoprad, datfname=mksrf_ftoprad, varname = 'SKY_VIEW', ndiag=ndiag, top_o=sky_view, nodata=1.0_r8) + call mktoprad(ldomain, mapfname=map_ftoprad, datfname=mksrf_ftoprad, varname = 'TERRAIN_CONFIG', ndiag=ndiag, top_o=terrain_config, nodata=0.0_r8) + + do n = 1,ns_o ! Assume wetland and/or lake when dataset landmask implies ocean @@ -797,6 +822,10 @@ program mksurfdat litho(n) = 0._r8 nfert(n,:) = 0._r8 pfert(n,:) = 0._r8 + sinsl_sinas(n) = 0._r8 + sinsl_cosas(n) = 0._r8 + sky_view(n) = 1._r8 + terrain_config(n)= 0._r8 else pftdata_mask(n) = 1 end if @@ -1103,6 +1132,18 @@ program mksurfdat call check_ret(nf_inq_varid(ncid, 'Litho', varid), subname) call check_ret(nf_put_var_double(ncid, varid, litho), subname) + call check_ret(nf_inq_varid(ncid, 'SINSL_SINAS', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, sinsl_sinas), subname) + + call check_ret(nf_inq_varid(ncid, 'SINSL_COSAS', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, sinsl_cosas), subname) + + call check_ret(nf_inq_varid(ncid, 'SKY_VIEW', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, sky_view), subname) + + call check_ret(nf_inq_varid(ncid, 'TERRAIN_CONFIG', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, terrain_config), subname) + ! Deallocate arrays NOT needed for dynamic-pft section of code deallocate ( organic ) @@ -1123,6 +1164,7 @@ program mksurfdat deallocate ( grvl, slp10 ) deallocate ( ero_c1, ero_c2, ero_c3, tillage, litho ) deallocate ( nfert, pfert ) + deallocate ( sinsl_sinas, sinsl_cosas, sky_view, terrain_config ) ! Synchronize the disk copy of a netCDF dataset with in-memory buffers call check_ret(nf_sync(ncid), subname) diff --git a/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 b/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 new file mode 100644 index 00000000000..e8ea66f9de4 --- /dev/null +++ b/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 @@ -0,0 +1,239 @@ +module mktopradMod +!----------------------------------------------------------------------- +!BOP +! +! !MODULE: mktopradMod +! +! !DESCRIPTION: +! Make topography data for TOP solar radiation parameterization +! +! !REVISION HISTORY: +! Author: Dalei Hao +! +!----------------------------------------------------------------------- +!!USES: + use shr_kind_mod, only : r8 => shr_kind_r8 + use shr_sys_mod , only : shr_sys_flush + implicit none + + SAVE + private ! By default make data private +! +! !PUBLIC MEMBER FUNCTIONS: +! + public mktopradAtt ! Add attributes to output file + + public mktoprad ! Set topography +! +! !PUBLIC DATA MEMBERS: +! +! +! !PRIVATE DATA MEMBERS: +! +! !PRIVATE MEMBER FUNCTIONS: + +!EOP +!=============================================================== +contains +!=============================================================== + +!----------------------------------------------------------------------- +!BOP +! +! !IROUTINE: mktoprad +! +! !INTERFACE: +subroutine mktoprad(ldomain, mapfname, datfname, varname, ndiag, top_o, nodata) +! +! !DESCRIPTION: +! Make topography data for TOP solar radiation parameterization +! +! !USES: + use mkdomainMod , only : domain_type, domain_clean, domain_read, domain_checksame + use mkgridmapMod + use mkvarpar + use mkvarctl + use mkncdio +! +! !ARGUMENTS: + implicit none + type(domain_type), intent(in) :: ldomain + character(len=*) , intent(in) :: mapfname ! input mapping file name + character(len=*) , intent(in) :: datfname ! input data file name + integer , intent(in) :: ndiag ! unit number for diag out + character(len=*) , intent(in) :: varname ! topo variable name + real(r8) , intent(out):: top_o(:) ! output topography data + real(r8) , intent(in) :: nodata ! default value +! +! +! !CALLED FROM: +! subroutine mksrfdat in module mksrfdatMod +! +! !REVISION HISTORY: +! Author: Dalei Hao +! +! +! !LOCAL VARIABLES: +!EOP + type(domain_type) :: tdomain ! local domain + type(gridmap_type) :: tgridmap ! local gridmap + + real(r8), allocatable :: top_i(:) ! input top variable + real(r8), allocatable :: mask_i(:) ! input grid: mask (0, 1) + integer :: ns_i,ns_o ! indices + integer :: k,l,n,m,ni ! indices + integer :: ncidi,dimid,varid ! input netCDF id's + integer :: ier ! error status + character(len=256) :: name ! name of attribute + character(len=256) :: unit ! units of attribute + character(len= 32) :: subname = 'mktop' +!----------------------------------------------------------------------- + + write (6,*) 'Attempting to make topography .....' + call shr_sys_flush(6) + + ns_o = ldomain%ns + + ! ----------------------------------------------------------------- + ! Read input file + ! ----------------------------------------------------------------- + + ! Obtain input grid info, read local fields + + call domain_read(tdomain,datfname) + + ns_i = tdomain%ns + allocate(top_i(ns_i), stat=ier) + if (ier /= 0) then + write(6,*)'mktoprad allocation error'; call abort() + end if + + write (6,*) 'Open topography file: ', trim(datfname) + call check_ret(nf_open(datfname, 0, ncidi), subname) + call check_ret(nf_inq_varid (ncidi, trim(varname), varid), subname) + call check_ret(nf_get_var_double (ncidi, varid, top_i), subname) + call check_ret(nf_close(ncidi), subname) + + ! Read topo dataset + call gridmap_mapread(tgridmap, mapfname) + + ! Error checks for domain and map consistencies + ! Note that the topo dataset has no landmask - so a unit landmask is assumed + + call domain_checksame( tdomain, ldomain, tgridmap ) + + ! Determine top_o on output grid + + top_o(:) = nodata + + call gridmap_areaave(tgridmap, top_i, top_o, nodata=nodata) + + ! Deallocate dynamic memory + + call domain_clean(tdomain) + call gridmap_clean(tgridmap) + deallocate (top_i) + + write (6,*) 'Successfully made topography parameters' + write (6,*) + call shr_sys_flush(6) + +end subroutine mktoprad + +!----------------------------------------------------------------------- + +!----------------------------------------------------------------------- +!BOP +! +! !IROUTINE: mktopradAtt +! +! !INTERFACE: +subroutine mktopradAtt( ncid, dynlanduse, xtype ) +! +! !DESCRIPTION: +! add atttributes to output file regarding the topography module +! +! !USES: + use fileutils , only : get_filename + use mkncdio , only : check_ret, ncd_defvar + use mkvarpar + use mkvarctl + +! !ARGUMENTS: + implicit none + include 'netcdf.inc' + integer, intent(in) :: ncid ! NetCDF file ID to write out to + logical, intent(in) :: dynlanduse ! if dynamic land-use file + integer, intent(in) :: xtype ! external type to output real data as +! +! !CALLED FROM: +! subroutine mkfile in module mkfileMod +! +! !REVISION HISTORY: +! Original Author: Dalei Hao +! +! +! !LOCAL VARIABLES: +!EOP + integer :: dimid ! temporary + character(len=256) :: str ! global attribute string + character(len=32) :: subname = 'mktopAtt' +!----------------------------------------------------------------------- + + if (.not. dynlanduse) then + + ! Add global attributes to file + + str = get_filename(mksrf_fgrvl) + call check_ret(nf_put_att_text(ncid, NF_GLOBAL, & + 'top_raw_data_file_name', len_trim(str), trim(str)), subname) + + ! Define variables + + if (outnc_1d) then + call ncd_defvar(ncid=ncid, varname='SINSL_COSAS', xtype=xtype, & + dim1name='gridcell',& + long_name='sin(slope) * cos(aspect)', units='unitless') + else + call ncd_defvar(ncid=ncid, varname='SINSL_COSAS', xtype=xtype, & + dim1name='lsmlon', dim2name='lsmlat', & + long_name='sin(slope) * cos(aspect)', units='unitless') + end if + + if (outnc_1d) then + call ncd_defvar(ncid=ncid, varname='SINSL_SINAS', xtype=xtype, & + dim1name='gridcell',& + long_name='sin(slope) * sin(aspect)', units='unitless') + else + call ncd_defvar(ncid=ncid, varname='SINSL_SINAS', xtype=xtype, & + dim1name='lsmlon', dim2name='lsmlat', & + long_name='sin(slope) * sin(aspect)', units='unitless') + end if + + if (outnc_1d) then + call ncd_defvar(ncid=ncid, varname='SKY_VIEW', xtype=xtype, & + dim1name='gridcell',& + long_name='sky view factor', units='unitless') + else + call ncd_defvar(ncid=ncid, varname='SKY_VIEW', xtype=xtype, & + dim1name='lsmlon', dim2name='lsmlat', & + long_name='sky view factor', units='unitless') + end if + + if (outnc_1d) then + call ncd_defvar(ncid=ncid, varname='TERRAIN_CONFIG', xtype=xtype, & + dim1name='gridcell',& + long_name='terrain configuration factor', units='unitless') + else + call ncd_defvar(ncid=ncid, varname='TERRAIN_CONFIG', xtype=xtype, & + dim1name='lsmlon', dim2name='lsmlat', & + long_name='terrain configuration factor', units='unitless') + end if + + end if + +end subroutine mktopradAtt + +!----------------------------------------------------------------------- + +end module mktopradMod diff --git a/components/elm/tools/mksurfdata_map/src/mkvarctl.F90 b/components/elm/tools/mksurfdata_map/src/mkvarctl.F90 index 48e74583374..127f0e83124 100644 --- a/components/elm/tools/mksurfdata_map/src/mkvarctl.F90 +++ b/components/elm/tools/mksurfdata_map/src/mkvarctl.F90 @@ -52,7 +52,8 @@ module mkvarctl character(len=256), public :: mksrf_fslp10 = ' ' ! slope percentile file name character(len=256), public :: mksrf_fero = ' ' ! ELM-Erosion parameters data file name character(len=256), public :: mksrf_ffert = ' ' ! crop fertilizer data file name - integer , public :: numpft = 16 ! number of plant types + character(len=256), public :: mksrf_ftoprad = ' ' ! topography parameters data file name for TOP solar radiation parameterization + integer , public :: numpft = 16 ! number of plant types character(len=256), public :: map_fpft = ' ' ! Mapping file for PFT character(len=256), public :: map_flakwat = ' ' ! Mapping file for lake water @@ -80,6 +81,7 @@ module mkvarctl character(len=256), public :: map_fslp10 = ' ' ! Mapping file for slope percentile character(len=256), public :: map_fero = ' ' ! Mapping file for ELM-Erosion parameters character(len=256), public :: map_ffert = ' ' ! Mapping file for crop fertilizer! + character(len=256), public :: map_ftoprad = ' ' ! Mapping file for topography parameters in TOP solar radiation parameterization ! ! Variables to override data read in with ! (all_urban is mostly for single-point mode, but could be used for sensitivity studies) From e99b394cf5930683eda564255ae8841fb57a73c2 Mon Sep 17 00:00:00 2001 From: hollyhan Date: Tue, 12 Mar 2024 00:09:08 -0600 Subject: [PATCH 068/388] Move 'deallocate' statement out of error-check --- .../mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F index f3bd15e57e8..51c9a8f69e2 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_bedtopo.F @@ -578,11 +578,10 @@ subroutine slmodel_init(domain, err) call sl_solver_checkpoint(itersl, dtime) call sl_solver_init(itersl, starttime, ismIceload, ismBedtopo, ismMask) call sl_deallocate_array - - deallocate(ismIceload, ismBedtopo, ismMask) - deallocate(bedtopoSLgrid1D, thicknessSLgrid1D, maskSLgrid1D) endif + deallocate(ismIceload, ismBedtopo, ismMask) + deallocate(bedtopoSLgrid1D, thicknessSLgrid1D, maskSLgrid1D) endif deallocate(globalArrayThickness) deallocate(gatheredArrayThickness) From a90e0e6301ab194b2878b093f15c5834a837bd53 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Wed, 13 Mar 2024 12:37:01 -0500 Subject: [PATCH 069/388] More changes for the icepack BGC interface Added flag to turn off BGC coupling between the ocean and sea ice: config_couple_bgc_fields=false Added black carbon conservation analysis member -track ocean black carbon flux Added carbon conservation check options in interfaces for both icepack and column Bugfixes to column package version: 1. Bugfixes to lateral melt BGC snow flux and ice flux 2. Bugfix to add_new_ice_bgc -replaces adjust_tracer_profile with simpler and more accurate version update_vertical_bio_tracers Define carbon molar mass in mpas constants Commented out problematic omp directives in icepack interface Corrections to some bgc Registry descriptions (still more to do) NOTE: Changed submodule path for Icepack to a branch that works with the BGC interface. nonBFB with BGC --- .gitmodules | 2 +- components/mpas-seaice/bld/build-namelist | 10 +- .../mpas-seaice/bld/build-namelist-section | 2 +- .../namelist_defaults_mpassi.xml | 2 +- .../namelist_definition_mpassi.xml | 16 +- components/mpas-seaice/cime_config/buildnml | 9 + components/mpas-seaice/driver/ice_comp_mct.F | 22 +- components/mpas-seaice/src/Registry.xml | 62 +- .../Registry_seaice_conservation_check.xml | 108 + .../mpas_seaice_conservation_check.F | 577 ++++- .../mpas-seaice/src/column/ice_algae.F90 | 9 +- .../mpas-seaice/src/column/ice_colpkg.F90 | 5 +- .../mpas-seaice/src/column/ice_therm_itd.F90 | 10 +- .../mpas-seaice/src/column/ice_zbgc.F90 | 214 +- .../src/shared/mpas_seaice_column.F | 342 ++- .../src/shared/mpas_seaice_constants.F | 2 +- .../src/shared/mpas_seaice_icepack.F | 2286 ++++------------- 17 files changed, 1607 insertions(+), 2071 deletions(-) diff --git a/.gitmodules b/.gitmodules index 2652b041ac8..84c10e97a8c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,7 +76,7 @@ [submodule "components/mpas-seaice/src/icepack"] path = components/mpas-seaice/src/icepack url = git@github.com:E3SM-Project/Icepack.git - branch = origin/njeffery/merge-fixes-to-bgc + branch = njeffery/merge-fixes-to-bgc [submodule "externals/haero"] path = externals/haero url = git@github.com:eagles-project/haero.git diff --git a/components/mpas-seaice/bld/build-namelist b/components/mpas-seaice/bld/build-namelist index 71f8a0e8c87..d8bfcaa68c0 100755 --- a/components/mpas-seaice/bld/build-namelist +++ b/components/mpas-seaice/bld/build-namelist @@ -628,12 +628,7 @@ add_default($nl, 'config_recover_tracer_means_check'); ################################## # Namelist group: column_package # ################################## - -if ($ice_bgc eq 'ice_bgc') { - add_default($nl, 'config_column_physics_type', 'val'=>"column_package"); -} else { - add_default($nl, 'config_column_physics_type'); -} +add_default($nl, 'config_column_physics_type'); add_default($nl, 'config_use_column_shortwave'); add_default($nl, 'config_use_column_vertical_thermodynamics'); if ($ice_bgc eq 'ice_bgc') { @@ -681,6 +676,7 @@ if ($ice_bgc eq 'ice_bgc') { add_default($nl, 'config_use_humics', 'val'=>".true."); add_default($nl, 'config_use_DON', 'val'=>".true."); add_default($nl, 'config_use_iron', 'val'=>".true."); + add_default($nl, 'config_couple_biogeochemistry_fields'); } else { add_default($nl, 'config_use_vertical_biochemistry', 'val'=>".false."); add_default($nl, 'config_use_vertical_tracers', 'val'=>".false."); @@ -694,6 +690,7 @@ if ($ice_bgc eq 'ice_bgc') { add_default($nl, 'config_use_humics', 'val'=>".false."); add_default($nl, 'config_use_DON', 'val'=>".false."); add_default($nl, 'config_use_iron', 'val'=>".false."); + add_default($nl, 'config_couple_biogeochemistry_fields', 'val'=>".false."); } add_default($nl, 'config_use_chlorophyll'); add_default($nl, 'config_use_macromolecules'); @@ -943,7 +940,6 @@ if ($iceberg_mode eq 'data') { add_default($nl, 'config_use_data_icebergs', 'val'=>"false"); } add_default($nl, 'config_salt_flux_coupling_type'); -add_default($nl, 'config_couple_biogeochemistry_fields'); add_default($nl, 'config_ice_ocean_drag_coefficient'); ############################### diff --git a/components/mpas-seaice/bld/build-namelist-section b/components/mpas-seaice/bld/build-namelist-section index 28a6053f050..8b6a06dd674 100644 --- a/components/mpas-seaice/bld/build-namelist-section +++ b/components/mpas-seaice/bld/build-namelist-section @@ -193,6 +193,7 @@ add_default($nl, 'config_use_floe_size_distribution'); # Namelist group: biogeochemistry # ################################### +add_default($nl, 'config_couple_biogeochemistry_fields'); add_default($nl, 'config_use_brine'); add_default($nl, 'config_use_vertical_zsalinity'); add_default($nl, 'config_use_vertical_biochemistry'); @@ -447,7 +448,6 @@ add_default($nl, 'config_min_friction_velocity'); add_default($nl, 'config_ocean_heat_transfer_type'); add_default($nl, 'config_sea_freezing_temperature_type'); add_default($nl, 'config_ocean_surface_type'); -add_default($nl, 'config_couple_biogeochemistry_fields'); add_default($nl, 'config_use_data_icebergs'); add_default($nl, 'config_salt_flux_coupling_type'); add_default($nl, 'config_ice_ocean_drag_coefficient'); diff --git a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml index e7abd738eb2..118cc1e2581 100644 --- a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml +++ b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml @@ -203,6 +203,7 @@ false +false false false false @@ -430,7 +431,6 @@ 'constant' 'mushy' 'free' -false false 'constant' 0.00536 diff --git a/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml b/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml index 53649226f8e..bee39c08070 100644 --- a/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml +++ b/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml @@ -955,6 +955,14 @@ Default: Defined in namelist_defaults.xml + +Couple ocean and seaice biogeochemical fields + +Valid values: true or false +Default: Defined in namelist_defaults.xml + + Use the brine height tracer @@ -2654,14 +2662,6 @@ Valid values: 'free' or 'non-free' Default: Defined in namelist_defaults.xml - - - -Valid values: true or false -Default: Defined in namelist_defaults.xml - - Use data iceberg meltwater forcing diff --git a/components/mpas-seaice/cime_config/buildnml b/components/mpas-seaice/cime_config/buildnml index 8a890c9ce47..955a64144f7 100755 --- a/components/mpas-seaice/cime_config/buildnml +++ b/components/mpas-seaice/cime_config/buildnml @@ -688,6 +688,15 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') lines.append('') lines.append('') lines.append(' - + + - + + + @@ -5306,7 +5328,7 @@ type="real" dimensions="nZBGCTracers nCategories nCells Time" units="mmol m-2 s-1" - description="Tracers are ordered: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m2/s, particulate iron in umol/m2/s, humic carbon, black carbon1 in mg/m2/s, black carbon2 in mg/m2/s, dust1 in mg/m2/s, dust2 in mg/m2/s, dust3 in mg/m2/s, dust4 in mg/m2/s" + description="Only bio tracers used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m2/s, particulate iron in umol/m2/s, humic carbon, black carbon1 in mg/m2/s, black carbon2 in mg/m2/s, dust1 in mg/m2/s, dust2 in mg/m2/s, dust3 in mg/m2/s, dust4 in mg/m2/s" icepack_name="flux_bion" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> @@ -5314,7 +5336,23 @@ type="real" dimensions="nZBGCTracers nCells Time" units="mmol m-3" - description="Tracers are ordered: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m3, particulate iron in umol/m3, humic carbon, black carbon1 in mg/m3, black carbon2 in mg/m3,dust1 in mg/m3, dust2 in mg/m3, dust3 in mg/m3, dust4 in mg/m3" + description="All bio tracers including those not used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m3, particulate iron in umol/m3, humic carbon, black carbon1 in mg/m3, black carbon2 in mg/m3,dust1 in mg/m3, dust2 in mg/m3, dust3 in mg/m3, dust4 in mg/m3" + icepack_name="ocean_bio" + packages="pkgColumnBiogeochemistry;pkgColumnPackage" + /> + + @@ -5426,6 +5464,10 @@ type="real" dimensions="nCells Time" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \brief Compute MPAS-Seaice analysis member +!> \author Nicole Jeffery +!> \date 11 Mar 2024 +!> \details +!> This routine conducts all computations to verify black carbon conservation +! +!----------------------------------------------------------------------- + + subroutine black_carbon_conservation(domain, err) + + type (domain_type), intent(inout) :: & + domain + + integer, intent(out) :: & + err !< Output: error flag + + type(block_type), pointer :: & + blockPtr + + type(MPAS_pool_type), pointer :: & + conservationCheckBlackCarbonAMPool, & + conservationCheckAMPool, & + conservationCheckAreaAMPool + + real(kind=RKIND), dimension(:), pointer :: & + initialBlackCarbon, & + finalBlackCarbon, & + blackCarbonChange, & + blackCarbonChangeFlux, & + netBlackCarbonFlux, & + absoluteBlackCarbonError, & + relativeBlackCarbonError, & + iceAreaCell, & + iceAreaCellInitial, & + accumAbsoluteBlackCarbonError, & + accumRelativeBlackCarbonError + + real(kind=RKIND), dimension(:), pointer :: & + blackCarbonConsAtmBlackCarbonFlux, & + blackCarbonConsOceanBlackCarbonFlux, & + blackCarbonConsAtmBC1Flux, & + blackCarbonConsAtmBC2Flux + + real(kind=RKIND), dimension(:), allocatable :: & + sumArray, & + sumArrayOut + + type(MPAS_pool_type), pointer :: & + meshPool, & + tracersAggregatePool, & + biogeochemistryPool, & + icestatePool + + real(kind=RKIND), dimension(:), pointer :: & + areaCell, & + totalAtmBlackCarbonFlux, & + totalOceanBlackCarbonFlux, & + oceanBlackCarbonFlux + + real(kind=RKIND), dimension(:,:), pointer :: & + atmosBlackCarbonFlux + + integer, dimension(:,:), pointer :: & + cellInHemisphere + + real(kind=RKIND), pointer :: & + dt, & + earthArea + + logical, pointer :: & + config_AM_conservationCheck_write_to_logfile + + real(kind=RKIND) :: & + totalAtmBlackCarbonCell, & + totalAtmBC1Cell, & + totalAtmBC2Cell, & + totalOceanBlackCarbonCell + + integer, pointer :: & + nCellsSolve, & + nHemispheres, & + nAccumulate + + type (MPAS_Time_Type) :: & + currTime, & + startTime + + integer :: & + iCell, & + iHemisphere, & + iSumPrev, & + ierr + + integer :: & + nVars, & + nZBGC, & + nSums + + real(kind=RKIND) :: & + fluxScale + + character(len=strKIND) :: & + timeStr, & + timeStrStart + + character(len=16) :: & + valStr + + err = 0 + + call MPAS_pool_get_config(domain % configs, "config_dt", dt) + call MPAS_pool_get_config(domain % configs, "config_AM_conservationCheck_write_to_logfile", & + config_AM_conservationCheck_write_to_logfile) + + !------------------------------------------------------------- + ! Net carbon flux to ice + !------------------------------------------------------------- + + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres) + + nVars = 4 + + nSums = nHemispheres * nVars + + allocate(sumArray(nSums)) + allocate(sumArrayOut(nSums)) + + sumArray = 0.0_RKIND + + blockPtr => domain % blocklist + do while (associated(blockPtr)) + + call MPAS_pool_get_dimension(blockPtr % dimensions, "nCellsSolve", nCellsSolve) + + call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool) + call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistryPool) + call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracersAggregatePool) + call MPAS_pool_get_subpool(blockPtr % structs, "icestate", icestatePool) + call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool) + + + call MPAS_pool_get_array(tracersAggregatePool, "iceAreaCell", iceAreaCell) + call MPAS_pool_get_array(icestatePool, "iceAreaCellInitial", iceAreaCellInitial) + call MPAS_pool_get_array(meshPool, "areaCell", areaCell) + call MPAS_pool_get_array(biogeochemistryPool, "totalAtmBlackCarbonFlux", totalAtmBlackCarbonFlux) + call MPAS_pool_get_array(biogeochemistryPool, "totalOceanBlackCarbonFlux", totalOceanBlackCarbonFlux) + call MPAS_pool_get_array(biogeochemistryPool, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) + call MPAS_pool_get_array(biogeochemistryPool, "oceanBlackCarbonFlux", oceanBlackCarbonFlux) + call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere) + + do iCell = 1, nCellsSolve + + ! compute total black carbon flux to ocean from individual fluxes + + nZBGC = 1 + totalAtmBC1Cell = atmosBlackCarbonFlux(nZBGC,iCell) * areaCell(iCell)* & + iceAreaCellInitial(iCell) + nZBGC = nZBGC+1 + totalAtmBC2Cell = atmosBlackCarbonFlux(nZBGC,iCell) * areaCell(iCell)* & + iceAreaCellInitial(iCell) + totalOceanBlackCarbonCell = oceanBlackCarbonFlux(iCell) * areaCell(iCell)* & + iceAreaCell(iCell) + totalAtmBlackCarbonCell = totalAtmBC1Cell + totalAtmBC2Cell + + do iHemisphere = 1, nHemispheres + iSumPrev = (iHemisphere-1) * nVars + if (cellInHemisphere(iHemisphere,iCell) == 1) then + sumArray(iSumPrev+1) = sumArray(iSumPrev+1) + totalAtmBlackCarbonCell + sumArray(iSumPrev+2) = sumArray(iSumPrev+2) + totalAtmBC1Cell + sumArray(iSumPrev+3) = sumArray(iSumPrev+3) + totalAtmBC2Cell + sumArray(iSumPrev+4) = sumArray(iSumPrev+4) + totalOceanBlackCarbonCell + endif + enddo ! iHemisphere + + enddo ! iCell + + blockPtr => blockPtr % next + enddo + + ! perform the sums over processors + call MPAS_dmpar_sum_real_array(domain % dminfo, nSums, sumArray, sumArrayOut) + + ! accumulate fluxes + call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckBlackCarbonAM", conservationCheckBlackCarbonAMPool) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsOceanBlackCarbonFlux", blackCarbonConsOceanBlackCarbonFlux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBlackCarbonFlux", blackCarbonConsAtmBlackCarbonFlux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBC1Flux", blackCarbonConsAtmBC1Flux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBC2Flux", blackCarbonConsAtmBC2Flux) + + do iHemisphere = 1, nHemispheres + iSumPrev = (iHemisphere-1) * nVars + blackCarbonConsAtmBlackCarbonFlux(iHemisphere) = blackCarbonConsAtmBlackCarbonFlux(iHemisphere) + sumArrayOut(iSumPrev+1) + blackCarbonConsAtmBC1Flux(iHemisphere) = blackCarbonConsAtmBC1Flux(iHemisphere) + sumArrayOut(iSumPrev+2) + blackCarbonConsAtmBC2Flux(iHemisphere) = blackCarbonConsAtmBC2Flux(iHemisphere) + sumArrayOut(iSumPrev+3) + blackCarbonConsOceanBlackCarbonFlux(iHemisphere) = blackCarbonConsOceanBlackCarbonFlux(iHemisphere) + sumArrayOut(iSumPrev+4) + enddo ! iHemisphere + + ! cleanup + deallocate(sumArray) + deallocate(sumArrayOut) + + !------------------------------------------------------------- + ! Black carbon conservation error + !------------------------------------------------------------- + + if (MPAS_stream_mgr_ringing_alarms(domain % streamManager, "conservationCheckOutput", ierr=ierr)) then + + ! convert fluxes to fluxes per m2 of whole earth and per second + call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool) + call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate) + call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAreaAM", conservationCheckAreaAMPool) + call MPAS_pool_get_array(conservationCheckAreaAMPool, "earthArea", earthArea) + fluxScale = 1.0_RKIND / (earthArea * real(nAccumulate)) + + ! get initial black carbon content + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "initialBlackCarbon", initialBlackCarbon) + + ! get final black carbon content + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "finalBlackCarbon", finalBlackCarbon) + call compute_total_black_carbon(domain, finalBlackCarbon) + + ! compute the black carbon content change + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonChange", blackCarbonChange) + blackCarbonChange(:) = finalBlackCarbon(:) - initialBlackCarbon(:) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonChangeFlux", blackCarbonChangeFlux) + blackCarbonChangeFlux(:) = blackCarbonChange(:) * (fluxScale / dt) + + ! calculate the final net black carbon flux to the ice + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "netBlackCarbonFlux", netBlackCarbonFlux) + netBlackCarbonFlux(:) = blackCarbonConsAtmBlackCarbonFlux(:) & + - blackCarbonConsOceanBlackCarbonFlux(:) + + ! absolute error + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "absoluteBlackCarbonError", absoluteBlackCarbonError) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "accumAbsoluteBlackCarbonError", accumAbsoluteBlackCarbonError) + absoluteBlackCarbonError(:) = netBlackCarbonFlux(:) * dt - blackCarbonChange(:) + + ! rescale fluxes + blackCarbonConsOceanBlackCarbonFlux(:) = blackCarbonConsOceanBlackCarbonFlux(:) * fluxScale + blackCarbonConsAtmBlackCarbonFlux(:) = blackCarbonConsAtmBlackCarbonFlux(:) * fluxScale + blackCarbonConsAtmBC1Flux(:) = blackCarbonConsAtmBC1Flux(:) * fluxScale + blackCarbonConsAtmBC2Flux(:) = blackCarbonConsAtmBC2Flux(:) * fluxScale + netBlackCarbonFlux(:) = netBlackCarbonFlux(:) * fluxScale + + ! compute the final black carbon error + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "relativeBlackCarbonError", relativeBlackCarbonError) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "accumRelativeBlackCarbonError", accumRelativeBlackCarbonError) + do iHemisphere = 1, nHemispheres + if (abs(finalBlackCarbon(iHemisphere)) > 0.0) then + relativeBlackCarbonError(iHemisphere) = absoluteBlackCarbonError(iHemisphere) / finalBlackCarbon(iHemisphere) + else + relativeBlackCarbonError(iHemisphere) = 0.0_RKIND + endif + enddo ! iHemisphere + + startTime = mpas_get_clock_time(domain % clock, MPAS_START_TIME, ierr=ierr) + currTime = mpas_get_clock_time(domain % clock, MPAS_NOW, ierr=ierr) + + call MPAS_get_time(currTime, dateTimeString=timeStr, ierr=ierr) + call MPAS_get_time(startTime, dateTimeString=timeStrStart, ierr=ierr) + + if (trim(timeStr) /= trim(timeStrStart)) then + accumRelativeBlackCarbonError(:) = accumRelativeBlackCarbonError(:) + relativeBlackCarbonError(:) + accumAbsoluteBlackCarbonError(:) = accumAbsoluteBlackCarbonError(:) + absoluteBlackCarbonError(:) + !------------------------------------------------------------- + ! Output to log file + !------------------------------------------------------------- + + if (config_AM_conservationCheck_write_to_logfile) then + + call mpas_log_write('-----------------------------------------------------------------------------') + call mpas_log_write(' Black carbon conservation check') + call mpas_log_write(' ') + call mpas_log_write(' Initial black carbon (kg) = '//trim(hemisphere_format(initialBlackCarbon))) + call mpas_log_write(' Final black carbon (kg) = '//trim(hemisphere_format(finalBlackCarbon))) + call mpas_log_write(' Black carbon change (kg) = '//trim(hemisphere_format(blackCarbonChange))) + call mpas_log_write(' Black carbon change flux (kg/m2s) = '//trim(hemisphere_format(blackCarbonChangeFlux))) + call mpas_log_write(' ') + call mpas_log_write(' Ocean black carbon flux (kg/m2s) = '//trim(hemisphere_format(blackCarbonConsOceanBlackCarbonFlux))) + call mpas_log_write(' Atmos black carbon flux (kg/m2s) = '//trim(hemisphere_format(blackCarbonConsAtmBlackCarbonFlux))) + call mpas_log_write(' Net black carbon flux (kg/m2s) = '//trim(hemisphere_format(netBlackCarbonFlux))) + call mpas_log_write(' ') + call mpas_log_write(' Individual atmosphere black carbon fluxes :') + call mpas_log_write(' Atmos BC1 flux (kg/m2s) = '//trim(hemisphere_format(blackCarbonConsAtmBC1Flux))) + call mpas_log_write(' Atmos BC2 flux (kg/m2s) = '//trim(hemisphere_format(blackCarbonConsAtmBC2Flux))) + call mpas_log_write(' ') + + call mpas_log_write(' Net black carbon change (kg) = '//trim(hemisphere_format((netBlackCarbonFlux * dt) / fluxScale))) + call mpas_log_write(' Net black carbon flux (kg/m2s) = '//trim(hemisphere_format(netBlackCarbonFlux))) + call mpas_log_write(' ') + call mpas_log_write(' Absolute black carbon error (kg) = '//trim(hemisphere_format(absoluteBlackCarbonError))) + call mpas_log_write(' Absolute BC error/s (kg/m2s) = '//trim(hemisphere_format((absoluteBlackCarbonError * fluxScale) / dt))) + call mpas_log_write(' Relative black carbon error = '//trim(hemisphere_format(relativeBlackCarbonError))) + + call mpas_log_write(' ') + call mpas_log_write(' Total run accumulated error ') + call mpas_log_write(' Accum. abs black carbon error(kg) = '//trim(hemisphere_format(accumAbsoluteBlackCarbonError))) + call mpas_log_write(' Accum. rel black carbon error = '//trim(hemisphere_format(accumRelativeBlackCarbonError))) + endif + endif + endif + + end subroutine black_carbon_conservation + !*********************************************************************** ! ! routine compute_total_energy @@ -2800,6 +3132,100 @@ subroutine compute_total_carbon(domain, totalCarbon) end subroutine compute_total_carbon +!*********************************************************************** +! +! routine compute_total_black_carbon +! +!> \brief Compute total black carbon +!> \author Nicole Jeffery +!> \date 11 Mar 2024 +!> \details +!> Calculate the total black carbon +! +!----------------------------------------------------------------------- + + subroutine compute_total_black_carbon(domain, totalBlackCarbon) + + type (domain_type), intent(inout) :: & + domain + + real(kind=RKIND), dimension(:), intent(out) :: & + totalBlackCarbon + + type(block_type), pointer :: & + blockPtr + + type(MPAS_pool_type), pointer :: & + meshPool, & + biogeochemistryPool, & + conservationCheckAMPool + + integer, pointer :: & + nCellsSolve, & + nHemispheres + + real(kind=RKIND), dimension(:), pointer :: & + totalBlackCarbonContentCell, & + areaCell + + integer, dimension(:,:), pointer :: & + cellInHemisphere + + integer :: & + iCell, & + iHemisphere + + real(kind=RKIND) :: & + blackCarbonCell + + real(kind=RKIND), dimension(:), allocatable :: & + blackCarbon + + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nHemispheres", nHemispheres) + + allocate(blackCarbon(nHemispheres)) + blackCarbon(:) = 0.0_RKIND + + blockPtr => domain % blocklist + do while (associated(blockPtr)) + + call MPAS_pool_get_subpool(blockPtr % structs, "mesh", meshPool) + call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistryPool) + call MPAS_pool_get_subpool(blockPtr % structs, "conservationCheckAM", conservationCheckAMPool) + + call MPAS_pool_get_dimension(blockPtr % dimensions, 'nCellsSolve', nCellsSolve) + call MPAS_pool_get_dimension(blockPtr % dimensions, 'nHemispheres', nHemispheres) + + call MPAS_pool_get_array(meshPool, "areaCell", areaCell) + call MPAS_pool_get_array(biogeochemistryPool, "totalBlackCarbonContentCell", totalBlackCarbonContentCell) + call MPAS_pool_get_array(conservationCheckAMPool, "cellInHemisphere", cellInHemisphere) + + call compute_black_carbon_cell(blockPtr,totalBlackCarbonContentCell) + + do iCell = 1, nCellsSolve + + ! black carbon mass (kg) + blackCarbonCell = totalBlackCarbonContentCell(iCell) * areaCell(iCell) + + do iHemisphere = 1, nHemispheres + if (cellInHemisphere(iHemisphere,iCell) == 1) then + blackCarbon(iHemisphere) = blackCarbon(iHemisphere) + blackCarbonCell + endif + enddo ! iHemisphere + + enddo ! iCell + + blockPtr => blockPtr % next + enddo + + ! sum across processors + call MPAS_dmpar_sum_real_array(domain % dminfo, nHemispheres, blackCarbon, totalBlackCarbon) + + ! clean up + deallocate(blackCarbon) + + end subroutine compute_total_black_carbon + !*********************************************************************** ! ! compute_carbon_cell @@ -3059,6 +3485,127 @@ subroutine compute_carbon_cell(blockPtr,totalCarbonContentCell) end subroutine compute_carbon_cell +!*********************************************************************** +! +! compute_black_carbon_cell +! +!> \brief +!> \author Nicole Jeffery, LANL +!> \date 11 Mar 2024 +!> \details Calculate the total carbon concentration in the sea ice cell +!> by summing the appropriate biogeochemical tracers in units of kg C +!> +!> Total black carbon = black carbon 1 + black carbon 2 +! +!----------------------------------------------------------------------- + + subroutine compute_black_carbon_cell(blockPtr,totalBlackCarbonContentCell) + + real(kind=RKIND), dimension(:), intent(out) :: & + totalBlackCarbonContentCell + + type(block_type), intent(in) :: & + blockPtr + + logical, pointer :: & + config_use_zaerosols + + integer, pointer :: & + nBioLayersP1, & + nBioLayersP3, & + nBioLayers, & + nzAerosols, & + maxBCType, & + TWO + + type(MPAS_pool_type), pointer :: & + mesh, & + biogeochemistry, & + tracers_aggregate + + real(kind=RKIND), dimension(:), pointer :: & + brineFractionCell, & + iceVolumeCell, & + snowVolumeCell + + real(kind=RKIND), dimension(:,:), pointer :: & + verticalAerosolsConcCell + + integer, pointer :: & + nCellsSolve, & + nSnowLayers + + real(kind=RKIND), dimension(:), allocatable :: & + verticalGridSpace + + real(kind=RKIND) :: & + snowleveltop, & + snowlevelint + + integer :: & + iBioTracers, & + iBioCount, & + iBioData, & + iCell, & + nBC + + call MPAS_pool_get_config(blockPtr % configs, "config_use_zaerosols",config_use_zaerosols) + + call MPAS_pool_get_dimension(blockPtr % dimensions, "nBioLayers", nBioLayers) + call MPAS_pool_get_dimension(blockPtr % dimensions, "nBioLayersP1", nBioLayersP1) + call MPAS_pool_get_dimension(blockPtr % dimensions, "nBioLayersP3", nBioLayersP3) + call MPAS_pool_get_dimension(blockPtr % dimensions, "nzAerosols", nzAerosols) + call MPAS_pool_get_dimension(blockPtr % dimensions, "maxBCType", maxBCType) + call MPAS_pool_get_dimension(blockPtr % dimensions, "TWO", TWO) + + call MPAS_pool_get_subpool(blockPtr % structs, "tracers_aggregate", tracers_aggregate) + call MPAS_pool_get_subpool(blockPtr % structs, "mesh", mesh) + call MPAS_pool_get_subpool(blockPtr % structs, "biogeochemistry", biogeochemistry) + + call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) + call MPAS_pool_get_dimension(mesh, 'nSnowLayers', nSnowLayers) + + call MPAS_pool_get_array(tracers_aggregate, "verticalAerosolsConcCell", verticalAerosolsConcCell) + call MPAS_pool_get_array(tracers_aggregate, "brineFractionCell", brineFractionCell) + call MPAS_pool_get_array(tracers_aggregate, "iceVolumeCell", iceVolumeCell) + call MPAS_pool_get_array(tracers_aggregate, "snowVolumeCell", snowVolumeCell) + + allocate(verticalGridSpace(nBioLayersP1)) + + verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) + verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND + verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) + + totalBlackCarbonContentCell(:) = 0.0_RKIND + + if (config_use_zaerosols) then + nBC = min(nzAerosols,maxBCType) + do iCell = 1, nCellsSolve + iBioCount = 0 + + ! BC + snowleveltop = snowVolumeCell(iCell)/real(nSnowLayers,kind=RKIND)/2.0_RKIND + snowlevelint = snowVolumeCell(iCell) - snowleveltop + do iBioTracers = 1, nBC + iBioData = (iBioTracers-1)*nBioLayersP3 + ! ice BC + do iBioCount = 1, nBioLayersP1 + totalBlackCarbonContentCell(iCell) = totalBlackCarbonContentCell(iCell) + & + verticalAerosolsConcCell(iBioData + iBioCount,iCell) * verticalGridSpace(iBioCount) * & + iceVolumeCell(iCell) * brineFractionCell(iCell) + end do + ! snow BC + totalBlackCarbonContentCell(iCell) = totalBlackCarbonContentCell(iCell) + & + verticalAerosolsConcCell(iBioData+nBioLayersP1+1,iCell) * snowleveltop + & + verticalAerosolsConcCell(iBioData+nBioLayersP1+2,iCell) * snowlevelint + enddo + enddo + endif + + deallocate(verticalGridSpace) + + end subroutine compute_black_carbon_cell + !*********************************************************************** ! ! routine reset_accumulated_variables @@ -3082,7 +3629,8 @@ subroutine reset_accumulated_variables(domain) conservationCheckEnergyAMPool, & conservationCheckMassAMPool, & conservationCheckSaltAMPool, & - conservationCheckCarbonAMPool + conservationCheckCarbonAMPool, & + conservationCheckBlackCarbonAMPool integer, pointer :: & nAccumulate @@ -3125,6 +3673,12 @@ subroutine reset_accumulated_variables(domain) carbonConsHumicsFlux, & carbonConsSemiLabileDOCFlux + real(kind=RKIND), dimension(:), pointer :: & + blackCarbonConsOceanBlackCarbonFlux, & + blackCarbonConsAtmBlackCarbonFlux, & + blackCarbonConsAtmBC1Flux, & + blackCarbonConsAtmBC2Flux + ! number of accumulations call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckAM", conservationCheckAMPool) call MPAS_pool_get_array(conservationCheckAMPool, "nAccumulate", nAccumulate) @@ -3209,6 +3763,19 @@ subroutine reset_accumulated_variables(domain) carbonConsHumicsFlux(:) = 0.0_RKIND carbonConsSemiLabileDOCFlux(:) = 0.0_RKIND + ! black carbon + + call MPAS_pool_get_subpool(domain % blocklist % structs, "conservationCheckBlackCarbonAM", conservationCheckBlackCarbonAMPool) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsOceanBlackCarbonFlux", blackCarbonConsOceanBlackCarbonFlux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBlackCarbonFlux", blackCarbonConsAtmBlackCarbonFlux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBC1Flux", blackCarbonConsAtmBC1Flux) + call MPAS_pool_get_array(conservationCheckBlackCarbonAMPool, "blackCarbonConsAtmBC2Flux", blackCarbonConsAtmBC2Flux) + + blackCarbonConsOceanBlackCarbonFlux(:) = 0.0_RKIND + blackCarbonConsAtmBlackCarbonFlux(:) = 0.0_RKIND + blackCarbonConsAtmBC1Flux(:) = 0.0_RKIND + blackCarbonConsAtmBC2Flux(:) = 0.0_RKIND + end subroutine reset_accumulated_variables !*********************************************************************** diff --git a/components/mpas-seaice/src/column/ice_algae.F90 b/components/mpas-seaice/src/column/ice_algae.F90 index 78dce86e2d3..e3fb475d72b 100644 --- a/components/mpas-seaice/src/column/ice_algae.F90 +++ b/components/mpas-seaice/src/column/ice_algae.F90 @@ -1325,7 +1325,8 @@ subroutine z_biogeochemistry (n_cat, dt, & trcrn(nt_zbgc_frac+mm-1) = zbgc_frac_init(mm) if (sum_tot > c0) trcrn(nt_zbgc_frac+mm-1) = sum_new/sum_tot - if (abs(sum_initial-sum_tot-flux_bio(mm)*dt + source(mm)) > accuracy*max(sum_initial,sum_tot) .or. & + if (abs(sum_initial-sum_tot-flux_bio(mm)*dt + source(mm)) > accuracy*max(sum_initial,sum_tot) .\ +or. & ! if (abs(sum_new-sum_old) > accuracy*sum_old .or. & minval(biocons(:)) < c0 .or. minval(initcons_stationary(:)) < c0 & .or. l_stop) then @@ -2874,8 +2875,8 @@ subroutine check_conservation_FCT & C_low(k) = C_new(k) enddo - accuracy = 1.0e-14_dbl_kind*max(c1, C_init_tot, C_new_tot) - fluxbio = (C_init_tot - C_new_tot + source)/dt + accuracy = 1.0e-11_dbl_kind*max(c1, C_init_tot, C_new_tot) + fluxbio = fluxbio + (C_init_tot - C_new_tot + source)/dt diff_dt =C_new_tot - C_init_tot - (S_top+S_bot+L_bot*C_new(nblyr+1)+L_top*C_new(1))*dt if (minval(C_low) < c0) then @@ -2885,7 +2886,7 @@ subroutine check_conservation_FCT & endif if (abs(diff_dt) > accuracy ) then - !l_stop = .true. + l_stop = .true. write(warning,*) 'Conservation of zbgc low order solution failed: diff_dt:',& diff_dt call add_warning(warning) diff --git a/components/mpas-seaice/src/column/ice_colpkg.F90 b/components/mpas-seaice/src/column/ice_colpkg.F90 index ce21d8a69ea..ee140abdbf7 100644 --- a/components/mpas-seaice/src/column/ice_colpkg.F90 +++ b/components/mpas-seaice/src/column/ice_colpkg.F90 @@ -5459,7 +5459,8 @@ subroutine colpkg_biogeochemistry(dt, & upNO, upNH, iDi, iki, zfswin, & zsal_tot, darcy_V, grow_net, & PP_net, hbri,dhbr_bot, dhbr_top, Zoo,& - fbio_snoice, fbio_atmice, ocean_bio, & + fbio_snoice, fbio_atmice, & + ocean_bio, & first_ice, fswpenln, bphi, bTiz, ice_bio_net, & snow_bio_net, totalChla, fswthrun, Rayleigh_criteria, & sice_rho, fzsal, fzsal_g, & @@ -5816,7 +5817,7 @@ subroutine colpkg_biogeochemistry(dt, & n_don, & n_fed, n_fep, & n_zaero, first_ice(n), & - hin_old(n), ocean_bio(:), & + hin_old(n), ocean_bio(1:nbtrcr), & bphi(:,n), iphin, & iDi(:,n), sss, & fswpenln(:,n), & diff --git a/components/mpas-seaice/src/column/ice_therm_itd.F90 b/components/mpas-seaice/src/column/ice_therm_itd.F90 index 81930d017e4..7adcbc9c1c6 100644 --- a/components/mpas-seaice/src/column/ice_therm_itd.F90 +++ b/components/mpas-seaice/src/column/ice_therm_itd.F90 @@ -913,7 +913,9 @@ subroutine lateral_melt (dt, ncat, & dvint ! snow interior layer real (kind=dbl_kind), dimension (ncat) :: & - vicen_init ! volume per unit area of ice (m) + vicen_init, & ! initial volume per unit area of ice (m) + aicen_init, & ! initial area + vsnon_init ! initial volume of snow (m) if (rside > c0) then ! grid cells with lateral melting. @@ -944,6 +946,8 @@ subroutine lateral_melt (dt, ncat, & ! state variables vicen_init(n) = vicen(n) + aicen_init(n) = aicen(n) + vsnon_init(n) = vsnon(n) aicen(n) = aicen(n) * (c1 - rside) vicen(n) = vicen(n) * (c1 - rside) vsnon(n) = vsnon(n) * (c1 - rside) @@ -980,8 +984,8 @@ subroutine lateral_melt (dt, ncat, & !----------------------------------------------------------------- if (z_tracers) then ! snow tracers - dvssl = min(p5*vsnon(n)/real(nslyr,kind=dbl_kind), hs_ssl*aicen(n)) !snow surface layer - dvint = vsnon(n)- dvssl !snow interior + dvssl = min(p5*vsnon_init(n)/real(nslyr,kind=dbl_kind), hs_ssl*aicen_init(n)) !snow surface layer + dvint = vsnon_init(n)- dvssl !snow interior do k = 1, nbtrcr flux_bio(k) = flux_bio(k) & + (trcrn(bio_index(k)+nblyr+1,n)*dvssl & diff --git a/components/mpas-seaice/src/column/ice_zbgc.F90 b/components/mpas-seaice/src/column/ice_zbgc.F90 index e8cef6dcad9..de31fbf702f 100644 --- a/components/mpas-seaice/src/column/ice_zbgc.F90 +++ b/components/mpas-seaice/src/column/ice_zbgc.F90 @@ -11,6 +11,7 @@ module ice_zbgc use ice_kinds_mod use ice_zbgc_shared ! everything + use ice_warnings, only: add_warning implicit none @@ -109,7 +110,8 @@ subroutine add_new_ice_bgc (dt, nblyr, & location , & ! 1 (add frazil to bottom), 0 (add frazil throughout) n , & ! ice category index k , & ! ice layer index - m + m , & + nbiolayer real (kind=dbl_kind) :: & vbri1 , & ! starting volume of existing brine @@ -119,12 +121,14 @@ subroutine add_new_ice_bgc (dt, nblyr, & real (kind=dbl_kind) :: & vsurp , & ! volume of new ice added to each cat vtmp ! total volume of new and old ice - + real (kind=dbl_kind), dimension (ncat) :: & - vbrin ! trcrn(nt_fbri,n)*vicen(n) + vbrin , & ! trcrn(nt_fbri,n)*vicen(n) + brine_frac_init ! initial trcrn(nt_fbri,n) real (kind=dbl_kind) :: & - vice_new ! vicen_init + vsurp + vice_new , & ! vicen_init + vsurp + bio0new ! ocean_bio * zbgc_init_fac real (kind=dbl_kind) :: & Tmlts ! melting temperature (oC) @@ -132,9 +136,8 @@ subroutine add_new_ice_bgc (dt, nblyr, & character (len=char_len) :: & fieldid ! field identifier - real (kind=dbl_kind), dimension (nbtrcr) :: & - total_bio_initial, & ! Initial column bio concentration (mmol/m2) - total_bio_final ! final column bio concentration (mmol/m2) + character(len=char_len_long) :: & + warning real (kind=dbl_kind), dimension (nblyr+1) :: & zspace ! vertical grid spacing @@ -152,19 +155,13 @@ subroutine add_new_ice_bgc (dt, nblyr, & if (tr_brine) vbrin(n) = trcrn(nt_fbri,n)*vicen_init(n) enddo - do m = 1, nbtrcr - total_bio_initial(m) = c0 - do n = 1, ncat - do k = 1, nblyr+1 - total_bio_initial(m) = total_bio_initial(m) + vbrin(n) * zspace(k)*trcrn(bio_index(m)+k-1,n) - enddo - enddo - enddo - call column_sum (ncat, vbrin, vbri_init) vbri_init = vbri_init + vi0_init + do k = 1, nbtrcr + flux_bio(k) = flux_bio(k) - vi0_init/dt*ocean_bio(k)*zbgc_init_frac(k) + enddo !----------------------------------------------------------------- ! Distribute bgc in new ice volume among all ice categories by ! increasing ice thickness, leaving ice area unchanged. @@ -178,34 +175,27 @@ subroutine add_new_ice_bgc (dt, nblyr, & vtmp = c0 do n = 1,ncat - - if (hsurp > c0) then + brine_frac_init(n) = c1 + if (hsurp > c0) then ! add ice to all categories vtmp = vbrin(n) - vsurp = hsurp * aicen_init(n) + vsurp = hsurp * aicen_init(n) vbrin(n) = vbrin(n) + vsurp vice_new = vicen_init(n) + vsurp - if (tr_brine .and. vicen(n) > c0) then - trcrn(nt_fbri,n) = vbrin(n)/vicen(n) + if (tr_brine .and. vice_new > c0) then ! NJvicen(n) > c0) then + brine_frac_init(n) = trcrn(nt_fbri,n) !NJ + trcrn(nt_fbri,n) = vbrin(n)/vice_new !NJ vicen(n) elseif (tr_brine .and. vicen(n) <= c0) then trcrn(nt_fbri,n) = c1 endif - if (nbtrcr > 0) then - location = 1 - call adjust_tracer_profile(nbtrcr, dt, ntrcr, & - aicen_init(n), & - vbrin(n), & - vice_new, & - trcrn(:,n), & - vtmp, & - vsurp, sss, & - nilyr, nblyr, & - solve_zsal, bgrid, & - cgrid, & - ocean_bio, igrid, & - location, & - l_stop, stop_label) + if (nbtrcr > 0) then + do m = 1, nbtrcr + bio0new = ocean_bio(m)*zbgc_init_frac(m) + nbiolayer = nblyr+1 + call update_vertical_bio_tracers(nbiolayer, trcrn(bio_index(m):bio_index(m) + nblyr,n), & + vtmp, vbrin(n), bio0new,zspace(:)) + enddo !nbtrcr if (l_stop) return endif ! nbtrcr endif ! hsurp > 0 @@ -214,36 +204,30 @@ subroutine add_new_ice_bgc (dt, nblyr, & !----------------------------------------------------------------- ! Combine bgc in new ice grown in open water with category 1 ice. !----------------------------------------------------------------- - + if (vi0new > c0) then - vbri1 = vbrin(1) + vbri1 = vbrin(1) vbrin(1) = vbrin(1) + vi0new if (tr_brine .and. vicen(1) > c0) then trcrn(nt_fbri,1) = vbrin(1)/vicen(1) elseif (tr_brine .and. vicen(1) <= c0) then trcrn(nt_fbri,1) = c1 endif - + ! Diffuse_bio handles concentration changes from ice growth/melt ! ice area changes ! add salt throughout, location = 0 - if (nbtrcr > 0) then - location = 0 - call adjust_tracer_profile(nbtrcr, dt, ntrcr, & - aicen(1), & - vbrin(1), & - vicen(1), & - trcrn(:,1), & - vbri1, & - vi0new, sss, & - nilyr, nblyr, & - solve_zsal, bgrid, & - cgrid, & - ocean_bio, igrid, & - location, & - l_stop, stop_label) + if (nbtrcr > 0 .and. vbrin(1) > c0) then + do m = 1, nbtrcr + bio0new = ocean_bio(m)*zbgc_init_frac(m) + do k = 1, nblyr+1 + trcrn(bio_index(m) + k-1,1) = & + (trcrn(bio_index(m) + k-1,1)*vbri1 + bio0new * vi0new)/vbrin(1) + enddo + enddo + if (l_stop) return if (solve_zsal .and. vsnon1 .le. c0) then @@ -253,16 +237,6 @@ subroutine add_new_ice_bgc (dt, nblyr, & endif ! nbtrcr > 0 endif ! vi0new > 0 - do m = 1, nbtrcr - total_bio_final(m) = c0 - do n = 1, ncat - do k = 1, nblyr+1 - total_bio_final(m) = total_bio_final(m) + trcrn(nt_fbri,n) * vicen(n) *zspace(k)*trcrn(bio_index(m)+k-1,n) - enddo - enddo - flux_bio(m) = flux_bio(m) + (total_bio_initial(m) - total_bio_final(m))/dt - enddo - if (tr_brine .and. l_conservation_check) then call column_sum (ncat, vbrin, vbri_final) @@ -320,10 +294,6 @@ subroutine lateral_melt_bgc (dt, & ! local variables - real (kind=dbl_kind) :: & - total_bio_initial, & ! initial column tracer concentration (mmol/m2) - total_bio_final ! final column tracer concentration (mmol/m20 - integer (kind=int_kind) :: & k , & ! layer index m , & ! @@ -332,9 +302,12 @@ subroutine lateral_melt_bgc (dt, & real (kind=dbl_kind), dimension (nblyr+1) :: & zspace ! vertical grid spacing + character(len=char_len_long) :: & + warning + zspace(:) = c1/real(nblyr,kind=dbl_kind) - zspace(1) = p5*zspace(1) - zspace(nblyr+1) = p5*zspace(nblyr+1) + zspace(1) = p5*zspace(2) + zspace(nblyr+1) = p5*zspace(nblyr) if (solve_zsal) then do n = 1, ncat @@ -347,15 +320,13 @@ subroutine lateral_melt_bgc (dt, & endif do m = 1, nbtrcr - total_bio_initial = c0 - total_bio_final = c0 do n = 1, ncat do k = 1, nblyr+1 - total_bio_initial = total_bio_initial + trcrn(nt_fbri,n) * vicen_init(n) *zspace(k)*trcrn(bio_index(m)+k-1,n) - total_bio_final = total_bio_final + trcrn(nt_fbri,n) * vicen(n) *zspace(k)*trcrn(bio_index(m)+k-1,n) + flux_bio(m) = flux_bio(m) + trcrn(nt_fbri,n) & + * vicen_init(n)*zspace(k)*trcrn(bio_index(m)+k-1,n) & + * rside/dt enddo - enddo - flux_bio(m) = flux_bio(m) + (total_bio_initial - total_bio_final)/dt + enddo enddo end subroutine lateral_melt_bgc @@ -462,7 +433,7 @@ subroutine adjust_tracer_profile (nbtrcr, dt, ntrcr, & hbri_old = vtmp if (solve_zsal) then top_conc = sss * salt_loss - do k = 1, nblyr + do k = 1, nblyr S_stationary(k) = trcrn(nt_bgc_S+k-1)* hbri_old enddo call regrid_stationary (S_stationary, hbri_old, & @@ -472,7 +443,7 @@ subroutine adjust_tracer_profile (nbtrcr, dt, ntrcr, & bgrid(2:nblyr+1), fluxb,& l_stop, stop_label) if (l_stop) return - do k = 1, nblyr + do k = 1, nblyr trcrn(nt_bgc_S+k-1) = S_stationary(k)/hbri trtmp0(nt_sice+k-1) = trcrn(nt_bgc_S+k-1) enddo @@ -480,7 +451,7 @@ subroutine adjust_tracer_profile (nbtrcr, dt, ntrcr, & do m = 1, nbtrcr top_conc = ocean_bio(m)*zbgc_init_frac(m) - do k = 1, nblyr+1 + do k = 1, nblyr+1 C_stationary(k) = trcrn(bio_index(m) + k-1)* hbri_old enddo !k call regrid_stationary (C_stationary, hbri_old, & @@ -789,6 +760,91 @@ subroutine merge_bgc_fluxes_skl (ntrcr, & enddo end subroutine merge_bgc_fluxes_skl +!======================================================================= +! +! Given some added new ice to the base of the existing ice, recalculate +! vertical bio tracer so that new grid cells are all the same size. +! +! author: N. Jeffery, LANL +! + subroutine update_vertical_bio_tracers(nbiolyr, trc, h1, h2, trc0, zspace) + + use ice_constants_colpkg, only: c0 + + integer (kind=int_kind), intent(in) :: & + nbiolyr ! number of bio layers nblyr+1 + + real (kind=dbl_kind), dimension(:), intent(inout) :: & + trc ! vertical tracer + + real (kind=dbl_kind), intent(in) :: & + h1, & ! old thickness + h2, & ! new thickness + trc0 ! tracer value of added ice on ice bottom + + real (kind=dbl_kind), dimension(nbiolyr), intent(in) :: & + zspace + + ! local variables + + real(kind=dbl_kind), dimension(nbiolyr) :: trc2 ! updated tracer temporary + + ! vertical indices for old and new grid + integer :: k1, k2 + + real (kind=dbl_kind) :: & + z1a, z1b, & ! upper, lower boundary of old cell/added new ice at bottom + z2a, z2b, & ! upper, lower boundary of new cell + overlap , & ! overlap between old and new cell + rnilyr + + !rnilyr = real(nilyr,dbl_kind) + z2a = c0 + z2b = c0 + ! loop over new grid cells + do k2 = 1, nbiolyr + + ! initialize new tracer + trc2(k2) = c0 + + ! calculate upper and lower boundary of new cell + z2a = z2b !((k2 - 1) * h2) * zspace(k2)+z2b ! / rnilyr + z2b = z2b + h2 * zspace(k2) !(k2 * h2) * zspace(k2)+z2a !/ rnilyr + + z1a = c0 + z1b = c0 + ! loop over old grid cells + do k1 = 1, nbiolyr + + ! calculate upper and lower boundary of old cell + z1a = z1b !((k1 - 1) * h1) * zspace(k1)+z1b !/ rnilyr + z1b = z1b + h1 * zspace(k1) !(k1 * h1) * zspace(k1)+z1a !/ rnilyr + + ! calculate overlap between old and new cell + overlap = max(min(z1b, z2b) - max(z1a, z2a), c0) + + ! aggregate old grid cell contribution to new cell + trc2(k2) = trc2(k2) + overlap * trc(k1) + + enddo ! k1 + + ! calculate upper and lower boundary of added new ice at bottom + z1a = h1 + z1b = h2 + + ! calculate overlap between added ice and new cell + overlap = max(min(z1b, z2b) - max(z1a, z2a), c0) + ! aggregate added ice contribution to new cell + trc2(k2) = trc2(k2) + overlap * trc0 + ! renormalize new grid cell + trc2(k2) = trc2(k2)/zspace(k2)/h2 !(rnilyr * trc2(k2)) / h2 + + enddo ! k2 + + ! update vertical tracer array with the adjusted tracer + trc = trc2 + + end subroutine update_vertical_bio_tracers !======================================================================= diff --git a/components/mpas-seaice/src/shared/mpas_seaice_column.F b/components/mpas-seaice/src/shared/mpas_seaice_column.F index cfebdab2e20..1b736c4b0cc 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_column.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_column.F @@ -2110,6 +2110,9 @@ subroutine column_itd_thermodynamics(domain, clock) colpkg_step_therm2, & colpkg_clear_warnings + use seaice_constants, only: & + seaicePuny + type(domain_type), intent(inout) :: domain type(MPAS_clock_type), intent(in) :: clock @@ -2202,13 +2205,13 @@ subroutine column_itd_thermodynamics(domain, clock) iBioLayers ! test carbon conservation - real(kind=RKIND), dimension(:), allocatable :: & + real(kind=RKIND), dimension(:,:), allocatable :: & totalCarbonCatFinal, & totalCarbonCatInitial, & - oceanBioFluxesTemp, & - verticalGridSpace + oceanBioFluxesTemp - real(kind=RKIND) :: & + real(kind=RKIND), dimension(:), allocatable :: & + verticalGridSpace, & oceanCarbonFlux, & totalCarbonFinal, & totalCarbonInitial, & @@ -2317,11 +2320,22 @@ subroutine column_itd_thermodynamics(domain, clock) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers)) - allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers)) + allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) allocate(verticalGridSpace(nBioLayersP1)) if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories)) - allocate(totalCarbonCatInitial(nCategories)) + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(oceanCarbonFlux(nCellsSolve)) + allocate(carbonError(nCellsSolve)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFinal(1)) + allocate(oceanCarbonFlux(1)) + allocate(carbonError(1)) endif verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) @@ -2337,8 +2351,10 @@ subroutine column_itd_thermodynamics(domain, clock) anyAbort = .false. !$omp parallel do default(shared) private(iCategory,iBioTracers,iBioData,& - !$omp& totalCarbonInitial,abortMessage,oceanBioFluxesTemp,totalCarbonFinal,& - !$omp& carbonError) firstprivate(newlyFormedIceLogical,oceanBioConcentrationsUsed) & + !$omp& totalCarbonInitial,totalCarbonCatInitial,totalCarbonCatFinal,& + !$omp& abortMessage,oceanBioFluxesTemp,totalCarbonFinal,& + !$omp& oceanCarbonFlux, carbonError) & + !$omp& firstprivate(newlyFormedIceLogical,oceanBioConcentrationsUsed) & !$omp& reduction(.or.:abortFlag) do iCell = 1, nCellsSolve @@ -2358,14 +2374,14 @@ subroutine column_itd_thermodynamics(domain, clock) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - totalCarbonInitial = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatInitial,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + totalCarbonInitial(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) do iCategory = 1,nCategories - totalCarbonInitial = totalCarbonInitial + totalCarbonCatInitial(iCategory)*iceAreaCategory(1,iCategory,iCell) + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) enddo endif - oceanBioFluxesTemp(:) = 0.0_RKIND + oceanBioFluxesTemp(:,iCell) = 0.0_RKIND call colpkg_clear_warnings() call colpkg_step_therm2(& @@ -2408,7 +2424,7 @@ subroutine column_itd_thermodynamics(domain, clock) oceanAerosolFlux(:,iCell), & newlyFormedIceLogical(:), & !first_ice, intent(inout) zSalinityFlux(iCell), & - oceanBioFluxesTemp(:), & + oceanBioFluxesTemp(:,iCell), & oceanBioConcentrationsUsed(:), & !ocean_bio, intent(in) abortFlag, & abortMessage, & @@ -2417,7 +2433,7 @@ subroutine column_itd_thermodynamics(domain, clock) dayOfYear) do iBioTracers = 1, ciceTracerObject % nBioTracers - oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers) + oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers,iCell) enddo call column_write_warnings(abortFlag) @@ -2433,26 +2449,26 @@ subroutine column_itd_thermodynamics(domain, clock) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - totalCarbonFinal = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxesTemp,iCell) + totalCarbonFinal(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell),iCell) do iCategory = 1,nCategories - totalCarbonFinal = totalCarbonFinal + totalCarbonCatFinal(iCategory)*iceAreaCategory(1,iCategory,iCell) + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) enddo - carbonError = totalCarbonInitial - oceanCarbonFlux*config_dt - totalCarbonFinal + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) - if (abs(carbonError) > 1.0e-14_RKIND*MAXVAL((/totalCarbonInitial,totalCarbonFinal/))) then + if (abs(carbonError(iCell)) > max(seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell)))) then call mpas_log_write("column_step_therm2, carbon conservation error", messageType=MPAS_LOG_ERR) call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError/)) - call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial/)) - call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal/)) - call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) + call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) + call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) do iCategory = 1, nCategories call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) enddo endif endif @@ -2472,10 +2488,12 @@ subroutine column_itd_thermodynamics(domain, clock) call seaice_critical_error_write_block(domain, block, anyAbort) call seaice_check_critical_error(domain, anyAbort) - if (checkCarbon) then - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - endif + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFinal) + deallocate(oceanCarbonFlux) + deallocate(carbonError) ! newly formed ice deallocate(newlyFormedIceLogical) @@ -3372,6 +3390,9 @@ subroutine column_ridging(domain) colpkg_step_ridge, & colpkg_clear_warnings + use seaice_constants, only: & + seaicePuny + type(domain_type), intent(inout) :: domain type(block_type), pointer :: block @@ -3408,7 +3429,8 @@ subroutine column_ridging(domain) nIceLayers, & nSnowLayers, & nAerosols, & - nBioLayers + nBioLayers, & + nBioLayersP1 ! variables real(kind=RKIND), dimension(:), pointer :: & @@ -3458,7 +3480,24 @@ subroutine column_ridging(domain) ! local integer :: & iCell, & - iCategory + iCategory, & + iBioTracers, & + iBioData, & + iBioLayers + + ! test carbon conservation + real(kind=RKIND), dimension(:,:), allocatable :: & + totalCarbonCatFinal, & + totalCarbonCatInitial, & + oceanBioFluxesTemp + + real(kind=RKIND), dimension(:), allocatable :: & + verticalGridSpace, & + oceanCarbonFlux, & + totalCarbonFinal, & + totalCarbonInitial, & + carbonError, & + iceAreaCategoryInitial logical, dimension(:), allocatable :: & newlyFormedIceLogical @@ -3466,12 +3505,15 @@ subroutine column_ridging(domain) logical :: & abortFlag, & setGetPhysicsTracers, & - setGetBGCTracers + setGetBGCTracers, & + checkCarbon character(len=strKIND) :: & abortMessage, & abortLocation + checkCarbon = .false. + block => domain % blocklist do while (associated(block)) @@ -3491,6 +3533,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_config(block % configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) + call MPAS_pool_get_config(block % configs, "config_dt", config_dt) call MPAS_pool_get_array(velocity_solver, "dynamicsTimeStep", dynamicsTimeStep) @@ -3500,6 +3543,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_dimension(mesh, "nSnowLayers", nSnowLayers) call MPAS_pool_get_dimension(mesh, "nAerosols", nAerosols) call MPAS_pool_get_dimension(block % dimensions, "nBioLayers", nBioLayers) + call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1) call MPAS_pool_get_array(mesh, "indexToCellID", indexToCellID) @@ -3546,6 +3590,30 @@ subroutine column_ridging(domain) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) + allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) + allocate(verticalGridSpace(nBioLayersP1)) + if (checkCarbon) then + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(oceanCarbonFlux(nCellsSolve)) + allocate(carbonError(nCellsSolve)) + allocate(iceAreaCategoryInitial(nCategories)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFinal(1)) + allocate(oceanCarbonFlux(1)) + allocate(carbonError(1)) + allocate(iceAreaCategoryInitial(1)) + endif + + verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) + verticalGridSpace(1) = verticalGridSpace(2)/2.0_RKIND + verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) + setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) @@ -3564,6 +3632,17 @@ subroutine column_ridging(domain) call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) + if (checkCarbon) then + totalCarbonInitial(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + do iCategory = 1,nCategories + iceAreaCategoryInitial(iCategory) = iceAreaCategory(1,iCategory,iCell) + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + enddo + endif + + oceanBioFluxesTemp(:,iCell) = 0.0_RKIND + call colpkg_clear_warnings() call colpkg_step_ridge(& dynamicsTimeStep, & @@ -3607,11 +3686,15 @@ subroutine column_ridging(domain) oceanSaltFlux(iCell), & newlyFormedIceLogical(:), & zSalinityFlux(iCell), & - oceanBioFluxes(:,iCell), & + oceanBioFluxesTemp(:,iCell), & abortFlag, & abortMessage) call column_write_warnings(abortFlag) + do iBioTracers = 1, ciceTracerObject % nBioTracers + oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers,iCell) + enddo + ! update do iCategory = 1, nCategories newlyFormedIce(iCategory,iCell) = 0 @@ -3622,6 +3705,35 @@ subroutine column_ridging(domain) call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) + if (checkCarbon) then + totalCarbonFinal(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell),iCell) + do iCategory = 1,nCategories + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + enddo + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) + + if (abs(carbonError(iCell)) > max(10.0_RKIND*seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell))) .and. & + MAXVAL(iceAreaCategory(1,:,iCell)) > seaicePuny .and. & + MAXVAL(iceAreaCategoryInitial(:)) > seaicePuny) then + call mpas_log_write("column_step_ridge, carbon conservation error", messageType=MPAS_LOG_ERR) + call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) + call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) + call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) + + do iCategory = 1, nCategories + call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategoryInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory)/)) + enddo + endif + endif + ! code abort if (abortFlag) then call mpas_log_write("column_ridging: "//trim(abortMessage) , messageType=MPAS_LOG_ERR) @@ -3635,6 +3747,16 @@ subroutine column_ridging(domain) call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) + deallocate(oceanBioFluxesTemp) + deallocate(verticalGridSpace) + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFinal) + deallocate(oceanCarbonFlux) + deallocate(carbonError) + deallocate(iceAreaCategoryInitial) + ! newly formed ice deallocate(newlyFormedIceLogical) @@ -3759,6 +3881,7 @@ subroutine column_biogeochemistry(domain) snowIceBioFluxes, & atmosIceBioFluxes, & oceanBioConcentrations, & + oceanBioConcentrationsInUse, & totalVerticalBiologyIce, & totalVerticalBiologySnow, & penetratingShortwaveFlux, & @@ -3823,7 +3946,7 @@ subroutine column_biogeochemistry(domain) iBioLayers ! test carbon conservation - real(kind=RKIND), dimension(:), allocatable :: & + real(kind=RKIND), dimension(:,:), allocatable :: & totalCarbonCatFinal, & totalCarbonCatInitial, & totalCarbonCatFlux, & @@ -3831,12 +3954,13 @@ subroutine column_biogeochemistry(domain) brineHeightCatFinal real(kind=RKIND), dimension(:), allocatable :: & - oceanBioConcentrationsUsed, & - iceCarbonInitialCategory, & - iceCarbonFinalCategory, & - iceCarbonFluxCategory, & - iceBrineInitialCategory, & - iceBrineFinalCategory + totalCarbonFinal, & + totalCarbonInitial, & + totalCarbonFlux, & + carbonError + + real(kind=RKIND):: & + errorCheck logical, dimension(:), allocatable :: & newlyFormedIceLogical @@ -3852,12 +3976,8 @@ subroutine column_biogeochemistry(domain) abortMessage, & abortLocation - real(kind=RKIND) :: & - carbonErrorCat, & - carbonErrorColumnPackage - real(kind=RKIND), parameter :: & - accuracy = 1.0e-14_RKIND + accuracy = 1.0e-13_RKIND ! test carbon conservation checkCarbon = .false. @@ -3932,6 +4052,7 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "snowIceBioFluxes", snowIceBioFluxes) call MPAS_pool_get_array(biogeochemistry, "atmosIceBioFluxes", atmosIceBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrations", oceanBioConcentrations) + call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrationsInUse", oceanBioConcentrationsInUse) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologyIce", totalVerticalBiologyIce) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologySnow", totalVerticalBiologySnow) call MPAS_pool_get_array(biogeochemistry, "zSalinityIceDensity", zSalinityIceDensity) @@ -3995,16 +4116,37 @@ subroutine column_biogeochemistry(domain) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) - allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers)) - allocate(brineHeightCatInitial(nCategories)) + allocate(brineHeightCatInitial(nCategories,nCellsSolve)) + allocate(carbonError(nCellsSolve)) if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories)) - allocate(totalCarbonCatInitial(nCategories)) - allocate(totalCarbonCatFlux(nCategories)) - allocate(brineHeightCatFinal(nCategories)) + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonCatFlux(nCategories,nCellsSolve)) + allocate(brineHeightCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFlux(nCellsSolve)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonCatFlux(1,1)) + allocate(brineHeightCatFinal(1,1)) + allocate(totalCarbonFinal(1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFlux(1)) endif + brineHeightCatInitial(:,:) = 0.0_RKIND + carbonError(:) = 0.0_RKIND + totalCarbonCatFinal(:,:) = 0.0_RKIND + totalCarbonCatInitial(:,:) = 0.0_RKIND + totalCarbonCatFlux(:,:) = 0.0_RKIND + brineHeightCatFinal(:,:) = 0.0_RKIND + totalCarbonFinal(:) = 0.0_RKIND + totalCarbonInitial(:) = 0.0_RKIND + totalCarbonFlux(:) = 0.0_RKIND + setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) @@ -4013,12 +4155,19 @@ subroutine column_biogeochemistry(domain) abortMessage = "" atmosBioFluxes(:,:) = 0.0_RKIND - + oceanBioConcentrationsInUse(:,:) = 0.0_RKIND + + !$offomp parallel do default(shared) private(iCategory,iBioTracers,iAlgae, iBioLayers) & + !$offomp& firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & + !$offomp& totalCarbonCatInitial, totalCarbonCatFinal, & + !$offomp& totalCarbonInitial, totalCarbonFinal, totalCarbonFlux, & + !$offomp& atmosDustFlux, bioShortwaveFluxCell, newlyFormedIce) + ! do iCell = 1, nCellsSolve ! newly formed ice do iCategory = 1, nCategories newlyFormedIceLogical(iCategory) = (newlyFormedIce(iCategory,iCell) == 1) - brineHeightCatInitial(iCategory) = brineFraction(1,iCategory,iCell) * & + brineHeightCatInitial(iCategory,iCell) = brineFraction(1,iCategory,iCell) * & iceVolumeCategoryInitial(iCategory,iCell)/(iceAreaCategoryInitial(iCategory,iCell) + seaicePuny) enddo ! iCategory rayleighCriteria = (rayleighCriteriaReal(iCell) > 0.5_RKIND) @@ -4067,14 +4216,20 @@ subroutine column_biogeochemistry(domain) do iBioTracers = 1, ciceTracerObject % nBioTracers iBioData = ciceTracerObject % index_LayerIndexToDataArray(iBioTracers) - oceanBioConcentrationsUsed(iBioTracers) = oceanBioConcentrations(iBioData,iCell) + oceanBioConcentrationsInUse(iBioTracers,iCell) = oceanBioConcentrations(iBioData,iCell) enddo ! iBioTracers call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) call seaice_total_carbon_content_category(block,& - totalCarbonCatInitial,iceAreaCategoryInitial,iceVolumeCategoryInitial,iCell) + if (checkCarbon) then + call seaice_total_carbon_content_category(block,& + totalCarbonCatInitial(:,iCell),iceAreaCategoryInitial(:,:),iceVolumeCategoryInitial(:,:),iCell) + totalCarbonInitial(iCell) = 0.0_RKIND + do iCategory = 1, nCategories + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategoryInitial(iCategory,iCell) + enddo + endif call colpkg_clear_warnings() call colpkg_biogeochemistry(& @@ -4096,7 +4251,7 @@ subroutine column_biogeochemistry(domain) verticalNitrogenLosses(:,:,iCell), & snowIceBioFluxes(:,iCell), & atmosIceBioFluxes(:,iCell), & - oceanBioConcentrationsUsed(:), & + oceanBioConcentrationsInUse(:,iCell), & newlyFormedIceLogical(:), & shortwaveLayerPenetration(:,:,iCell), & bioPorosity(:,:,iCell), & @@ -4161,35 +4316,43 @@ subroutine column_biogeochemistry(domain) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux(block,totalCarbonCatFlux,oceanBioFluxesCategory(:,:,:),iCell) - do iCategory = 1,nCategories - brineHeightCatFinal(iCategory) = brineFraction(1,iCategory,iCell) * & + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux(block,totalCarbonCatFlux(:,iCell),oceanBioFluxesCategory(:,:,:),iCell) + totalCarbonFinal(iCell) = 0.0_RKIND + totalCarbonFlux(iCell) = 0.0_RKIND + do iCategory = 1, nCategories + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + totalCarbonFlux(iCell) = totalCarbonFlux(iCell) + totalCarbonCatFlux(iCategory,iCell) * iceAreaCategory(1,iCategory,iCell) + enddo + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + totalCarbonFlux(iCell) + errorCheck = MAX(accuracy,accuracy*abs(totalCarbonFlux(iCell))) + + if (abs(carbonError(iCell)) > errorCheck) then + do iCategory = 1,nCategories + if (iceAreaCategory(1,iCategory,iCell) > seaicePuny) then + brineHeightCatFinal(iCategory,iCell) = brineFraction(1,iCategory,iCell) * & iceVolumeCategory(1,iCategory,iCell)/(iceAreaCategory(1,iCategory,iCell) + seaicePuny) - carbonErrorCat = totalCarbonCatInitial(iCategory) - totalCarbonCatFlux(iCategory)*config_dt - & - totalCarbonCatFinal(iCategory) - if (abs(carbonErrorCat) > accuracy*MAXVAL((/totalCarbonCatInitial(iCategory),totalCarbonCatFinal(iCategory)/))) then -! abortFlag = .true. -! abortMessage = "carbon conservation errror after column bgc" - call mpas_log_write("column_biogeochemistry, carbon conservation error", messageType=MPAS_LOG_ERR) - call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("carbonErrorCat: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat/)) - call mpas_log_write("carbonErrorCat*iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat*iceAreaCategory(1,iCategory,iCell)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory)/)) - call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) - call mpas_log_write("totalCarbonCatFlux(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFlux(iCategory)/)) - call mpas_log_write("brineHeightCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatInitial(iCategory)/)) - call mpas_log_write("brineHeightCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatFinal(iCategory)/)) - endif - enddo - endif + call mpas_log_write("column_biogeochemistry, carbon conservation error", messageType=MPAS_LOG_ERR) + call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) + call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("carbonError*iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)*iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategoryInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatFlux(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFlux(iCategory,iCell)/)) + call mpas_log_write("brineHeightCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatInitial(iCategory,iCell)/)) + call mpas_log_write("brineHeightCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatFinal(iCategory,iCell)/)) + endif + enddo + endif !carbonError + endif ! code abort if (abortFlag) then call mpas_log_write("column_biogeochemistry: "//trim(abortMessage) , messageType=MPAS_LOG_ERR) call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - exit endif totalSkeletalAlgae(iCell) = 0.0_RKIND @@ -4222,16 +4385,17 @@ subroutine column_biogeochemistry(domain) call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) - if (checkCarbon) then - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - deallocate(totalCarbonCatFlux) - deallocate(brineHeightCatFinal) - endif + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonCatFlux) + deallocate(brineHeightCatFinal) + deallocate(totalCarbonFinal) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFlux) deallocate(brineHeightCatInitial) deallocate(newlyFormedIceLogical) - deallocate(oceanBioConcentrationsUsed) + deallocate(carbonError) block => block % next end do diff --git a/components/mpas-seaice/src/shared/mpas_seaice_constants.F b/components/mpas-seaice/src/shared/mpas_seaice_constants.F index 9a36d97b091..5c6a270704b 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_constants.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_constants.F @@ -187,7 +187,7 @@ module seaice_constants ! biogeochemistry constants real(kind=RKIND), public :: & skeletalLayerThickness = 0.03_RKIND ,&! (m) skeletal layer thickness - gramsCarbonPerMolCarbon ! g carbon per mol carbon + gramsCarbonPerMolCarbon = 12.0107_RKIND ! g carbon per mol carbon ! ocean biogeochemistry ISPOL values real(kind=RKIND), parameter, public :: & diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index fe3b3d5e977..05e6f98f337 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -2092,6 +2092,9 @@ subroutine column_itd_thermodynamics(domain, clock) use icepack_intfc, only: & icepack_step_therm2 + use seaice_constants, only: & + seaicePuny + type(domain_type), intent(inout) :: domain type(MPAS_clock_type), intent(in) :: clock @@ -2171,6 +2174,7 @@ subroutine column_itd_thermodynamics(domain, clock) oceanAerosolFlux, & oceanBioFluxes, & oceanBioConcentrations, & + oceanBioConcentrationsInUse, & initialSalinityProfile ! WaveSpectra, & ! DFloeSizeNewIce, & @@ -2200,21 +2204,18 @@ subroutine column_itd_thermodynamics(domain, clock) iBioLayers ! test carbon conservation - real(kind=RKIND), dimension(:), allocatable :: & + real(kind=RKIND), dimension(:,:), allocatable :: & totalCarbonCatFinal, & totalCarbonCatInitial, & - oceanBioFluxesTemp, & - verticalGridSpace + oceanBioFluxesTemp - real(kind=RKIND) :: & - oceanCarbonFlux, & + real(kind=RKIND), dimension(:), allocatable :: & + verticalGridSpace, & totalCarbonFinal, & totalCarbonInitial, & + oceanCarbonFlux, & carbonError - real(kind=RKIND), dimension(:), allocatable :: & - oceanBioConcentrationsUsed - logical, dimension(:), allocatable :: & newlyFormedIceLogical @@ -2319,6 +2320,7 @@ subroutine column_itd_thermodynamics(domain, clock) call MPAS_pool_get_array(biogeochemistry, "newlyFormedIce", newlyFormedIce) call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxes", oceanBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrations", oceanBioConcentrations) + call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrationsInUse", oceanBioConcentrationsInUse) call MPAS_pool_get_array(biogeochemistry, "biologyGrid", biologyGrid) call MPAS_pool_get_array(biogeochemistry, "verticalGrid", verticalGrid) call MPAS_pool_get_array(biogeochemistry, "interfaceBiologyGrid", interfaceBiologyGrid) @@ -2330,12 +2332,22 @@ subroutine column_itd_thermodynamics(domain, clock) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) - allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers)) - allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers)) + allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) allocate(verticalGridSpace(nBioLayersP1)) if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories)) - allocate(totalCarbonCatInitial(nCategories)) + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(oceanCarbonFlux(nCellsSolve)) + allocate(carbonError(nCellsSolve)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFinal(1)) + allocate(oceanCarbonFlux(1)) + allocate(carbonError(1)) endif verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) @@ -2345,14 +2357,17 @@ subroutine column_itd_thermodynamics(domain, clock) setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) + oceanBioConcentrationsInUse(:,:) = 0.0_RKIND ! code abort abortFlag = .false. abortMessage = "" - !$omp parallel do default(shared) private(iCategory,iBioTracers,iBioData,& - !$omp& totalCarbonInitial,abortMessage,oceanBioFluxesTemp,totalCarbonFinal,& - !$omp& carbonError) firstprivate(newlyFormedIceLogical,oceanBioConcentrationsUsed) & - !$omp& reduction(.or.:abortFlag) + !$offomp parallel do default(shared) private(iCategory,iBioTracers,iBioData,& + !$offomp& totalCarbonInitial,abortMessage,oceanBioFluxesTemp,totalCarbonFinal,& + !$offomp& totalCarbonCatInitial, totalCarbonCatFinal, & + !$offomp& oceanCarbonFlux, carbonError) & + !$offomp& firstprivate(newlyFormedIceLogical) & + !$offomp& reduction(.or.:abortFlag) do iCell = 1, nCellsSolve ! newly formed ice @@ -2363,7 +2378,7 @@ subroutine column_itd_thermodynamics(domain, clock) ! read the required ocean concentration fields into the allocated array do iBioTracers = 1, ciceTracerObject % nBioTracers iBioData = ciceTracerObject % index_LayerIndexToDataArray(iBioTracers) - oceanBioConcentrationsUsed(iBioTracers) = oceanBioConcentrations(iBioData, iCell) + oceanBioConcentrationsInUse(iBioTracers, iCell) = oceanBioConcentrations(iBioData, iCell) enddo ! iBioTracers ! set the category tracer array @@ -2371,14 +2386,14 @@ subroutine column_itd_thermodynamics(domain, clock) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - totalCarbonInitial = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatInitial,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + totalCarbonInitial(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) do iCategory = 1,nCategories - totalCarbonInitial = totalCarbonInitial + totalCarbonCatInitial(iCategory)*iceAreaCategory(1,iCategory,iCell) + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) enddo endif - oceanBioFluxesTemp(:) = 0.0_RKIND + oceanBioFluxesTemp(:,iCell) = 0.0_RKIND ! CICE calculates the Sig Wave Height from the wave spectrum as follows before step therm2: ! we will use the Sig Wave Height from WW3, but could use this for testing without WW3 @@ -2387,10 +2402,10 @@ subroutine column_itd_thermodynamics(domain, clock) call icepack_step_therm2(& dt=config_dt, & ncat=nCategories, & - nltrcr=ciceTracerObject % nBioTracers, & ! CHECK/FIX for BGC nilyr=nIcelayers, & nslyr=nSnowLayers, & hin_max=categoryThicknessLimits(:), & + nbtrcr=ciceTracerObject % nBioTracers, & nblyr=nBioLayers, & aicen=iceAreaCategory(1,:,iCell), & vicen=iceVolumeCategory(1,:,iCell), & @@ -2423,8 +2438,8 @@ subroutine column_itd_thermodynamics(domain, clock) igrid=interfaceBiologyGrid(:), & faero_ocn=oceanAerosolFlux(:,iCell), & first_ice=newlyFormedIceLogical(:), & - flux_bio=oceanBioFluxesTemp(:), & - ocean_bio=oceanBioConcentrationsUsed(:), & + flux_bio=oceanBioFluxesTemp(:,iCell), & + ocean_bio=oceanBioConcentrationsInUse(:,iCell), & frazil_diag=frazilGrowthDiagnostic(iCell), & frz_onset=freezeOnset(iCell), & ! optional yday=dayOfYear) ! optional @@ -2442,9 +2457,13 @@ subroutine column_itd_thermodynamics(domain, clock) ! d_afsd_newi=DFloeSizeNewIce(:,iCell), & ! d_afsd_latm=DFloeSizeLateralMelt(:,iCell), & ! d_afsd_weld=DFloeSizeWeld(:,iCell), & -! floe_rad_c=FloeSizeBinCenter(:), & +! floe_rad_c=FloeSizeBinCenter(:), & ! floe_binwidth=FloeSizeBinWidth(:)) + do iBioTracers = 1, ciceTracerObject % nBioTracers + oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers,iCell) + enddo + abortFlag = icepack_warnings_aborted() call seaice_icepack_write_warnings(abortFlag) @@ -2459,26 +2478,31 @@ subroutine column_itd_thermodynamics(domain, clock) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - totalCarbonFinal = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxesTemp,iCell) + totalCarbonFinal(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell)) do iCategory = 1,nCategories - totalCarbonFinal = totalCarbonFinal + totalCarbonCatFinal(iCategory)*iceAreaCategory(1,iCategory,iCell) + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) enddo - carbonError = totalCarbonInitial - oceanCarbonFlux*config_dt - totalCarbonFinal + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) - if (abs(carbonError) > 1.0e-14_RKIND*MAXVAL((/totalCarbonInitial,totalCarbonFinal/))) then + if (abs(carbonError(iCell)) > max(seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell)))) then call mpas_log_write("column_step_therm2, carbon conservation error", messageType=MPAS_LOG_ERR) call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError/)) - call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial/)) - call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal/)) - call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) + call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) + call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) + call mpas_log_write("config_dt: $r", messageType=MPAS_LOG_ERR, realArgs=(/config_dt/)) do iCategory = 1, nCategories call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) + call mpas_log_write("iceAreaCategoryInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory,iCell)/)) + call mpas_log_write("iceVolumeCategoryInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategoryInitial(iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceVolumeCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategory(1,iCategory,iCell)/)) enddo endif endif @@ -2495,14 +2519,15 @@ subroutine column_itd_thermodynamics(domain, clock) call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) - if (checkCarbon) then - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - endif + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFinal) + deallocate(oceanCarbonFlux) + deallocate(carbonError) ! newly formed ice deallocate(newlyFormedIceLogical) - deallocate(oceanBioConcentrationsUsed) deallocate(oceanBioFluxesTemp) deallocate(verticalGridSpace) @@ -3285,6 +3310,9 @@ subroutine column_ridging(domain) use icepack_intfc, only: & icepack_step_ridge + use seaice_constants, only: & + seaicePuny + type(domain_type), intent(inout) :: domain type(block_type), pointer :: block @@ -3321,7 +3349,8 @@ subroutine column_ridging(domain) nIceLayers, & nSnowLayers, & nAerosols, & - nBioLayers + nBioLayers, & + nBioLayersP1 ! variables real(kind=RKIND), dimension(:), pointer :: & @@ -3370,14 +3399,34 @@ subroutine column_ridging(domain) ! local integer :: & iCell, & - iCategory + iCategory, & + iBioTracers, & + iBioData, & + iBioLayers + + ! test carbon conservation + real(kind=RKIND), dimension(:,:), allocatable :: & + totalCarbonCatFinal, & + totalCarbonCatInitial, & + oceanBioFluxesTemp + + real(kind=RKIND), dimension(:), allocatable :: & + verticalGridSpace, & + totalCarbonFinal, & + totalCarbonInitial, & + oceanCarbonFlux, & + carbonError, & + iceAreaCategoryInitial logical, dimension(:), allocatable :: & newlyFormedIceLogical logical :: & setGetPhysicsTracers, & - setGetBGCTracers + setGetBGCTracers, & + checkCarbon + + checkCarbon = .false. block => domain % blocklist do while (associated(block)) @@ -3398,6 +3447,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_config(block % configs, "config_dynamics_subcycle_number", config_dynamics_subcycle_number) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) + call MPAS_pool_get_config(block % configs, "config_dt", config_dt) call MPAS_pool_get_array(velocity_solver, "dynamicsTimeStep", dynamicsTimeStep) @@ -3407,6 +3457,7 @@ subroutine column_ridging(domain) call MPAS_pool_get_dimension(mesh, "nSnowLayers", nSnowLayers) call MPAS_pool_get_dimension(mesh, "nAerosols", nAerosols) call MPAS_pool_get_dimension(block % dimensions, "nBioLayers", nBioLayers) + call MPAS_pool_get_dimension(block % dimensions, "nBioLayersP1", nBioLayersP1) call MPAS_pool_get_array(mesh, "indexToCellID", indexToCellID) @@ -3455,6 +3506,30 @@ subroutine column_ridging(domain) setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) + allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) + allocate(verticalGridSpace(nBioLayersP1)) + if (checkCarbon) then + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(oceanCarbonFlux(nCellsSolve)) + allocate(carbonError(nCellsSolve)) + allocate(iceAreaCategoryInitial(nCategories)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFinal(1)) + allocate(oceanCarbonFlux(1)) + allocate(carbonError(1)) + allocate(iceAreaCategoryInitial(1)) + endif + + verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) + verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND + verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) + do iCell = 1, nCellsSolve ! newly formed ice @@ -3466,6 +3541,17 @@ subroutine column_ridging(domain) call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) + if (checkCarbon) then + totalCarbonInitial(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + do iCategory = 1,nCategories + iceAreaCategoryInitial(iCategory) = iceAreaCategory(1,iCategory,iCell) + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + enddo + endif + + oceanBioFluxesTemp(:,iCell) = 0.0_RKIND + call icepack_step_ridge(& dt=dynamicsTimeStep, & ndtd=config_dynamics_subcycle_number, & @@ -3506,7 +3592,7 @@ subroutine column_ridging(domain) aice=iceAreaCell(iCell), & fsalt=oceanSaltFlux(iCell), & first_ice=newlyFormedIceLogical(:), & - flux_bio=oceanBioFluxes(:,iCell), & ! DC no closing argument + flux_bio=oceanBioFluxesTemp(:,iCell), & Tf=seaFreezingTemperature(iCell)) ! update @@ -3515,13 +3601,58 @@ subroutine column_ridging(domain) if (newlyFormedIceLogical(iCategory)) newlyFormedIce(iCategory,iCell) = 1 enddo ! iCategory + do iBioTracers = 1, ciceTracerObject % nBioTracers + oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers,iCell) + enddo + ! get category tracer array call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) + if (checkCarbon) then + totalCarbonFinal(iCell) = 0.0_RKIND + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell)) + do iCategory = 1,nCategories + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + enddo + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) + + if (abs(carbonError(iCell)) > max(10.0_RKIND*seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell))) .and. & + MAXVAL(iceAreaCategory(1,:,iCell)) > seaicePuny .and. & + MAXVAL(iceAreaCategoryInitial(:)) > seaicePuny) then + call mpas_log_write("icepack_step_ridge, carbon conservation error", messageType=MPAS_LOG_ERR) + call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) + call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) + call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) + call mpas_log_write("config_dt: $r", messageType=MPAS_LOG_ERR, realArgs=(/config_dt/)) + + do iCategory = 1, nCategories + call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategoryInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory)/)) + call mpas_log_write("iceVolumeCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategory(1,iCategory,iCell)/)) + enddo + endif + endif + enddo ! iCell call seaice_icepack_write_warnings(icepack_warnings_aborted()) +! check carbon + deallocate(oceanBioFluxesTemp) + deallocate(verticalGridSpace) + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFinal) + deallocate(oceanCarbonFlux) + deallocate(carbonError) + deallocate(iceAreaCategoryInitial) ! newly formed ice deallocate(newlyFormedIceLogical) @@ -3591,7 +3722,8 @@ subroutine column_biogeochemistry(domain) nBioLayersP1, & nAlgae, & maxBCType, & - maxDustType + maxDustType, & + maxAerosolType ! variables @@ -3630,6 +3762,8 @@ subroutine column_biogeochemistry(domain) snowIceBioFluxes, & atmosIceBioFluxes, & oceanBioConcentrations, & + oceanBioConcentrationsInUse, & + oceanBioToIceInUse, & totalVerticalBiologyIce, & totalVerticalBiologySnow, & penetratingShortwaveFlux, & @@ -3690,10 +3824,12 @@ subroutine column_biogeochemistry(domain) iSnowCount, & iIceCount, & indexj, & - iBioLayers + iBioLayers, & + iWarning, & + nWarnings ! test carbon conservation - real(kind=RKIND), dimension(:), allocatable :: & + real(kind=RKIND), dimension(:,:), allocatable :: & totalCarbonCatFinal, & totalCarbonCatInitial, & totalCarbonCatFlux, & @@ -3701,12 +3837,12 @@ subroutine column_biogeochemistry(domain) brineHeightCatFinal real(kind=RKIND), dimension(:), allocatable :: & - oceanBioConcentrationsUsed, & - iceCarbonInitialCategory, & - iceCarbonFinalCategory, & - iceCarbonFluxCategory, & - iceBrineInitialCategory, & - iceBrineFinalCategory + totalCarbonFinal, & + totalCarbonInitial, & + totalCarbonFlux + + real(kind=RKIND) :: & + errorCheck logical, dimension(:), allocatable :: & newlyFormedIceLogical @@ -3721,12 +3857,11 @@ subroutine column_biogeochemistry(domain) abortMessage, & abortLocation - real(kind=RKIND) :: & - carbonErrorCat, & - carbonErrorColumnPackage + real(kind=RKIND), dimension(:), allocatable :: & + carbonError real(kind=RKIND), parameter :: & - accuracy = 1.0e-14_RKIND + accuracy = 1.0e-13_RKIND ! test carbon conservation checkCarbon = .false. @@ -3787,6 +3922,8 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "snowIceBioFluxes", snowIceBioFluxes) call MPAS_pool_get_array(biogeochemistry, "atmosIceBioFluxes", atmosIceBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrations", oceanBioConcentrations) + call MPAS_pool_get_array(biogeochemistry, "oceanBioConcentrationsInUse", oceanBioConcentrationsInUse) + call MPAS_pool_get_array(biogeochemistry, "oceanBioToIceInUse", oceanBioToIceInUse) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologyIce", totalVerticalBiologyIce) call MPAS_pool_get_array(biogeochemistry, "totalVerticalBiologySnow", totalVerticalBiologySnow) call MPAS_pool_get_array(biogeochemistry, "atmosBioFluxes", atmosBioFluxes) @@ -3846,36 +3983,61 @@ subroutine column_biogeochemistry(domain) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) - allocate(oceanBioConcentrationsUsed(ciceTracerObject % nBioTracers)) - allocate(brineHeightCatInitial(nCategories)) + allocate(brineHeightCatInitial(nCategories,nCellsSolve)) + allocate(carbonError(nCellsSolve)) if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories)) - allocate(totalCarbonCatInitial(nCategories)) - allocate(totalCarbonCatFlux(nCategories)) - allocate(brineHeightCatFinal(nCategories)) + allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) + allocate(totalCarbonCatFlux(nCategories,nCellsSolve)) + allocate(brineHeightCatFinal(nCategories,nCellsSolve)) + allocate(totalCarbonFinal(nCellsSolve)) + allocate(totalCarbonInitial(nCellsSolve)) + allocate(totalCarbonFlux(nCellsSolve)) + else + allocate(totalCarbonCatFinal(1,1)) + allocate(totalCarbonCatInitial(1,1)) + allocate(totalCarbonCatFlux(1,1)) + allocate(brineHeightCatFinal(1,1)) + allocate(totalCarbonFinal(1)) + allocate(totalCarbonInitial(1)) + allocate(totalCarbonFlux(1)) endif + brineHeightCatInitial(:,:) = 0.0_RKIND + carbonError(:) = 0.0_RKIND + totalCarbonCatFinal(:,:) = 0.0_RKIND + totalCarbonCatInitial(:,:) = 0.0_RKIND + totalCarbonCatFlux(:,:) = 0.0_RKIND + brineHeightCatFinal(:,:) = 0.0_RKIND + totalCarbonFinal(:) = 0.0_RKIND + totalCarbonInitial(:) = 0.0_RKIND + totalCarbonFlux(:) = 0.0_RKIND + setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) atmosBioFluxes(:,:) = 0.0_RKIND - - !$omp parallel do default(shared) private(iCategory,iBioTracers,iAlgae) & - !$omp& firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & - !$omp& atmosDustFlux, bioShortwaveFluxCell, newlyFormedIce) + oceanBioConcentrationsInUse(:,:) = 0.0_RKIND + oceanBioToIceInUse(:,:) = 0.0_RKIND + + !$offomp parallel do default(shared) private(iCategory,iBioTracers,iAlgae, iBioLayers) & + !$offomp& firstprivate(atmosBioFluxes,atmosBlackCarbonFlux, & + !$offomp& totalCarbonCatInitial, totalCarbonCatFinal, & + !$offomp& totalCarbonInitial, totalCarbonFinal, totalCarbonFlux, & + !$offomp& atmosDustFlux, bioShortwaveFluxCell, newlyFormedIce) ! do iCell = 1, nCellsSolve ! newly formed ice do iCategory = 1, nCategories newlyFormedIceLogical(iCategory) = (newlyFormedIce(iCategory,iCell) == 1) - brineHeightCatInitial(iCategory) = brineFraction(1,iCategory,iCell) * & + brineHeightCatInitial(iCategory,iCell) = brineFraction(1,iCategory,iCell) * & iceVolumeCategoryInitial(iCategory,iCell)/(iceAreaCategoryInitial(iCategory,iCell) + seaicePuny) enddo ! iCategory !update ocean concentrations fields and atmospheric fluxes into allocated array -#ifdef coupled +#ifdef coupled call icepack_load_ocean_bio_array(& nit=oceanNitrateConc(iCell), & amm=oceanAmmoniumConc(iCell), & @@ -3891,7 +4053,6 @@ subroutine column_biogeochemistry(domain) zaeros=oceanZAerosolConc(:,iCell), & ocean_bio_all=oceanBioConcentrations(:,iCell), & hum=oceanHumicsConc(iCell)) - #else do iBioTracers = 1, maxBCType atmosBlackCarbonFlux(iBioTracers,iCell) = 1.e-12_RKIND @@ -3912,14 +4073,20 @@ subroutine column_biogeochemistry(domain) do iBioTracers = 1, ciceTracerObject % nBioTracers iBioData = ciceTracerObject % index_LayerIndexToDataArray(iBioTracers) - oceanBioConcentrationsUsed(iBioTracers) = oceanBioConcentrations(iBioData,iCell) + oceanBioConcentrationsInUse(iBioTracers,iCell) = oceanBioConcentrations(iBioData,iCell) enddo ! iBioTracers call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) call seaice_total_carbon_content_category(block,& - totalCarbonCatInitial,iceAreaCategoryInitial,iceVolumeCategoryInitial,iCell) + if (checkCarbon) then + call seaice_total_carbon_content_category(block,& + totalCarbonCatInitial(:,iCell),iceAreaCategoryInitial(:,:),iceVolumeCategoryInitial(:,:),iCell) + totalCarbonInitial(iCell) = 0.0_RKIND + do iCategory = 1, nCategories + totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategoryInitial(iCategory,iCell) + enddo + endif ! code abort abortFlag = .false. @@ -3942,7 +4109,8 @@ subroutine column_biogeochemistry(domain) Zoo=verticalNitrogenLosses(:,:,iCell), & fbio_snoice=snowIceBioFluxes(:,iCell), & fbio_atmice=atmosIceBioFluxes(:,iCell), & - ocean_bio=oceanBioConcentrationsUsed(:), & + ocean_bio_dh=oceanBioToIceInUse(:,iCell), & + ocean_bio=oceanBioConcentrationsInUse(:,iCell), & first_ice=newlyFormedIceLogical(:), & fswpenln=shortwaveLayerPenetration(:,:,iCell), & bphi=bioPorosity(:,:,iCell), & @@ -3991,29 +4159,39 @@ subroutine column_biogeochemistry(domain) tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) if (checkCarbon) then - call seaice_total_carbon_content_category(block,totalCarbonCatFinal,iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux(block,totalCarbonCatFlux,oceanBioFluxesCategory(:,:,:),iCell) - do iCategory = 1,nCategories - brineHeightCatFinal(iCategory) = brineFraction(1,iCategory,iCell) * & - iceVolumeCategory(1,iCategory,iCell)/(iceAreaCategory(1,iCategory,iCell) + seaicePuny) - carbonErrorCat = totalCarbonCatInitial(iCategory) - totalCarbonCatFlux(iCategory)*config_dt - & - totalCarbonCatFinal(iCategory) - if (abs(carbonErrorCat) > accuracy*MAXVAL((/totalCarbonCatInitial(iCategory),totalCarbonCatFinal(iCategory)/))) then -! abortFlag = .true. -! abortMessage = "carbon conservation errror after column bgc" - call mpas_log_write("column_biogeochemistry, carbon conservation error", messageType=MPAS_LOG_ERR) - call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("carbonErrorCat: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat/)) - call mpas_log_write("carbonErrorCat*iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonErrorCat*iceAreaCategory(1,iCategory,iCell)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory)/)) - call mpas_log_write("totalCarbonCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory)/)) - call mpas_log_write("totalCarbonCatFlux(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFlux(iCategory)/)) - call mpas_log_write("brineHeightCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatInitial(iCategory)/)) - call mpas_log_write("brineHeightCatFinal(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatFinal(iCategory)/)) - endif + call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) + call seaice_ocean_carbon_flux(block,totalCarbonCatFlux(:,iCell),oceanBioFluxesCategory(:,:,:),iCell) + totalCarbonFinal(iCell) = 0.0_RKIND + totalCarbonFlux(iCell) = 0.0_RKIND + do iCategory = 1, nCategories + totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) + totalCarbonFlux(iCell) = totalCarbonFlux(iCell) + totalCarbonCatFlux(iCategory,iCell) * iceAreaCategory(1,iCategory,iCell) enddo - endif + carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt +totalCarbonFlux(iCell) + errorCheck = max(accuracy,accuracy*abs(totalCarbonFlux(iCell))) + + if (abs(carbonError(iCell)) > errorCheck) then + do iCategory = 1,nCategories + if (iceAreaCategory(1,iCategory,iCell) > seaicePuny) then + brineHeightCatFinal(iCategory,iCell) = brineFraction(1,iCategory,iCell) * & + iceVolumeCategory(1,iCategory,iCell)/(iceAreaCategory(1,iCategory,iCell) + seaicePuny) + call mpas_log_write("column_biogeochemistry, carbon conservation error", messageType=MPAS_LOG_ERR) + call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) + call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) + call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) + call mpas_log_write("carbonError*iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)*iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + call mpas_log_write("iceAreaCategoryInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) + call mpas_log_write("totalCarbonCatFlux(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFlux(iCategory,iCell)/)) + call mpas_log_write("brineHeightCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatInitial(iCategory,iCell)/)) + call mpas_log_write("brineHeightCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/brineHeightCatFinal(iCategory,iCell)/)) + call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) + end if + enddo !categories + endif ! carbonError + endif ! checkCarbon totalSkeletalAlgae(iCell) = 0.0_RKIND bioShortwaveFluxCell(:,iCell) = 0.0_RKIND @@ -4047,16 +4225,17 @@ subroutine column_biogeochemistry(domain) call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) - if (checkCarbon) then - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - deallocate(totalCarbonCatFlux) - deallocate(brineHeightCatFinal) - endif + deallocate(totalCarbonCatFinal) + deallocate(totalCarbonCatInitial) + deallocate(totalCarbonCatFlux) + deallocate(brineHeightCatFinal) + deallocate(totalCarbonFinal) + deallocate(totalCarbonInitial) + deallocate(totalCarbonFlux) deallocate(brineHeightCatInitial) deallocate(newlyFormedIceLogical) - deallocate(oceanBioConcentrationsUsed) + deallocate(carbonError) block => block % next end do @@ -4585,6 +4764,7 @@ subroutine seaice_icepack_coupling_prep(domain) oceanDMSPdFlux, & oceanHumicsFlux, & oceanDustIronFlux, & + oceanBlackCarbonFlux, & totalOceanCarbonFlux real(kind=RKIND), dimension(:,:), pointer :: & @@ -4725,6 +4905,7 @@ subroutine seaice_icepack_coupling_prep(domain) call MPAS_pool_get_array(biogeochemistry, "oceanDMSPdFlux", oceanDMSPdFlux) call MPAS_pool_get_array(biogeochemistry, "oceanHumicsFlux", oceanHumicsFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDustIronFlux", oceanDustIronFlux) + call MPAS_pool_get_array(biogeochemistry, "oceanBlackCarbonFlux", oceanBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxes", oceanBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanAlgaeFlux", oceanAlgaeFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDOCFlux", oceanDOCFlux) @@ -4857,6 +5038,7 @@ subroutine seaice_icepack_coupling_prep(domain) oceanDMSPdFlux(iCell) = 0.0_RKIND oceanDMSFlux(iCell) = 0.0_RKIND oceanDustIronFlux(iCell) = 0.0_RKIND + oceanBlackCarbonFlux(iCell) = 0.0_RKIND oceanHumicsFlux(iCell) = 0.0_RKIND do iBioTracers = 1, ciceTracerObject % nBioTracers @@ -4939,8 +5121,11 @@ subroutine seaice_icepack_coupling_prep(domain) oceanParticulateIronFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) enddo - ! Black Carbon (not saved) - iBioData = iBioData + maxBCType + ! Black Carbon (combined; saved for conservation) + do iBioTracers = 1, maxBCType + iBioData = iBioData + 1 + oceanBlackCarbonFlux(iCell) = oceanBlackCarbonFlux(iCell) + oceanBioFluxesAll(iBioData) + enddo ! Dust (combined) do iBioTracers = 1, maxDustType @@ -5034,6 +5219,7 @@ subroutine seaice_column_scale_fluxes(domain) oceanDMSPpFlux, & oceanDMSPdFlux, & oceanHumicsFlux, & + oceanBlackCarbonFlux, & oceanDustIronFlux real(kind=RKIND), dimension(:,:), pointer :: & @@ -5116,6 +5302,7 @@ subroutine seaice_column_scale_fluxes(domain) call MPAS_pool_get_array(biogeochemistry, "oceanDMSPdFlux", oceanDMSPdFlux) call MPAS_pool_get_array(biogeochemistry, "oceanHumicsFlux", oceanHumicsFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDustIronFlux", oceanDustIronFlux) + call MPAS_pool_get_array(biogeochemistry, "oceanBlackCarbonFlux", oceanBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "oceanAlgaeFlux", oceanAlgaeFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDOCFlux", oceanDOCFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDICFlux", oceanDICFlux) @@ -5156,8 +5343,10 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = albedoVisibleDiffuseCell(iCell) * iceAreaInverse albedoIRDiffuseCell(iCell) = albedoIRDiffuseCell(iCell) * iceAreaInverse - if (config_use_zaerosols) & + if (config_use_zaerosols) then oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) * iceAreaInverse + oceanBlackCarbonFlux(iCell) = oceanBlackCarbonFlux(iCell) * iceAreaInverse + end if if (config_use_column_biogeochemistry) then @@ -5210,8 +5399,10 @@ subroutine seaice_column_scale_fluxes(domain) albedoVisibleDiffuseCell(iCell) = 0.0_RKIND albedoIRDiffuseCell(iCell) = 0.0_RKIND - if (config_use_zaerosols) & - oceanDustIronFlux(iCell) = 0.0_RKIND + if (config_use_zaerosols) then + oceanDustIronFlux(iCell) = 0.0_RKIND + oceanBlackCarbonFlux(iCell) = 0.0_RKIND + end if if (config_use_column_biogeochemistry) then @@ -9125,7 +9316,6 @@ subroutine init_icepack_package_parameters(domain, tracerObject) call init_icepack_package_tracer_indices(tracerObject) ! set the column parameters - call init_column_package_configs(domain) !echmod - temporary until colpkg_constants are moved call init_icepack_package_configs(domain) end subroutine init_icepack_package_parameters @@ -9654,7 +9844,7 @@ subroutine init_icepack_package_tracer_flags(domain) tr_pond_in = use_meltponds, & tr_pond_lvl_in = config_use_level_meltponds, & tr_pond_topo_in = config_use_topo_meltponds, & - !tr_fsd_in = , & + !tr_fsd_in = config_use_floe_size_distribution, & tr_aero_in = config_use_aerosols, & !tr_iso_in = , & tr_brine_in = config_use_brine, & @@ -9837,203 +10027,84 @@ end subroutine init_icepack_package_tracer_indices !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! -! init_column_package_configs +! init_icepack_package_configs ! !> \brief -!> \author Adrian K. Turner, LANL -!> \date 2nd Feburary 2015 +!> \author Adrian K. Turner, Elizabeth Hunke, Darin Comeau, Nicole Jeffery, Andrew Roberts, Erin Thomas, Jon Wolfe, LANL, Anthony Craig, NOAA (cntr), David Bailey, NCAR +!> \date 2022-2023 !> \details !> ! !----------------------------------------------------------------------- - subroutine init_column_package_configs(domain) !colpkg routine - remove - - !use ice_colpkg_shared, only: & - ! ktherm, & - ! conduct, & - ! fbot_xfer_type, & - ! heat_capacity, & - ! calc_Tsfc, & - ! ustar_min, & - ! a_rapid_mode, & - ! Rac_rapid_mode, & - ! aspect_rapid_mode, & - ! dSdt_slow_mode, & - ! phi_c_slow_mode, & - ! phi_i_mushy, & - ! shortwave, & - ! albedo_type, & - ! albicev, & - ! albicei, & - ! albsnowv, & - ! albsnowi, & - ! ahmax, & - ! R_ice, & - ! R_pnd, & - ! R_snw, & - ! dT_mlt, & - ! rsnw_mlt, & - ! kalg, & - ! kstrength, & - ! krdg_partic, & - ! krdg_redist, & - ! mu_rdg, & - ! Cf, & - ! atmbndy, & - ! calc_strair, & - ! formdrag, & - ! highfreq, & - ! natmiter, & - ! oceanmixed_ice, & - ! tfrz_option, & - ! kitd, & - ! kcatbound, & - ! hs0, & - ! frzpnd, & - ! dpscale, & - ! rfracmin, & - ! rfracmax, & - ! pndaspect, & - ! hs1, & - ! hp1 - ! bgc_flux_type, & - ! z_tracers, & - ! scale_bgc, & - ! solve_zbgc, & - ! dEdd_algae, & - ! modal_aero, & - ! skl_bgc, & - ! solve_zsal, & - ! grid_o, & - ! l_sk, & - ! grid_o_t, & - ! initbio_frac, & - ! frazil_scav, & - ! grid_oS, & - ! l_skS, & - ! 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 , & - ! ratio_Fe2N_diatoms, & - ! ratio_Fe2N_sp , & - ! ratio_Fe2N_phaeo , & - ! ratio_Fe2DON , & - ! ratio_Fe2DOC_s , & - ! ratio_Fe2DOC_l , & - ! fr_resp , & - ! tau_min , & - ! tau_max , & - ! algal_vel , & - ! R_dFe2dust , & - ! dustFe_sol , & - ! chlabs_diatoms , & - ! chlabs_sp , & - ! chlabs_phaeo , & - ! alpha2max_low_diatoms , & - ! alpha2max_low_sp , & - ! alpha2max_low_phaeo , & - ! beta2max_diatoms , & - ! beta2max_sp , & - ! beta2max_phaeo , & - ! mu_max_diatoms , & - ! mu_max_sp , & - ! mu_max_phaeo , & - ! grow_Tdep_diatoms, & - ! grow_Tdep_sp , & - ! grow_Tdep_phaeo , & - ! fr_graze_diatoms , & - ! fr_graze_sp , & - ! fr_graze_phaeo , & - ! mort_pre_diatoms , & - ! mort_pre_sp , & - ! mort_pre_phaeo , & - ! mort_Tdep_diatoms, & - ! mort_Tdep_sp , & - ! mort_Tdep_phaeo , & - ! k_exude_diatoms , & - ! k_exude_sp , & - ! k_exude_phaeo , & - ! K_Nit_diatoms , & - ! K_Nit_sp , & - ! K_Nit_phaeo , & - ! K_Am_diatoms , & - ! K_Am_sp , & - ! K_Am_phaeo , & - ! K_Sil_diatoms , & - ! K_Sil_sp , & - ! K_Sil_phaeo , & - ! K_Fe_diatoms , & - ! K_Fe_sp , & - ! K_Fe_phaeo , & - ! f_don_protein , & - ! kn_bac_protein , & - ! f_don_Am_protein , & - ! f_doc_s , & - ! f_doc_l , & - ! f_exude_s , & - ! f_exude_l , & - ! k_bac_s , & - ! k_bac_l , & - ! T_max , & - ! fsal , & - ! op_dep_min , & - ! fr_graze_s , & - ! fr_graze_e , & - ! fr_mort2min , & - ! fr_dFe , & - ! k_nitrif , & - ! t_iron_conv , & - ! max_loss , & - ! max_dfe_doc1 , & - ! fr_resp_s , & - ! y_sk_DMS , & - ! t_sk_conv , & - ! t_sk_ox , & - ! algaltype_diatoms , & - ! algaltype_sp , & - ! algaltype_phaeo , & - ! nitratetype , & - ! ammoniumtype , & - ! silicatetype , & - ! dmspptype , & - ! dmspdtype , & - ! humtype , & - ! doctype_s , & - ! doctype_l , & - ! dontype_protein , & - ! fedtype_1 , & - ! feptype_1 , & - ! zaerotype_bc1 , & - ! zaerotype_bc2 , & - ! zaerotype_dust1 , & - ! zaerotype_dust2 , & - ! zaerotype_dust3 , & - ! zaerotype_dust4 , & - ! ratio_C2N_diatoms , & - ! ratio_C2N_sp , & - ! ratio_C2N_phaeo , & - ! ratio_chl2N_diatoms, & - ! ratio_chl2N_sp , & - ! ratio_chl2N_phaeo , & - ! F_abs_chl_diatoms , & - ! F_abs_chl_sp , & - ! F_abs_chl_phaeo , & - ! ratio_C2N_proteins - - use ice_colpkg, only: & - colpkg_init_parameters + subroutine init_icepack_package_configs(domain) + + use icepack_intfc, only: & + icepack_init_parameters, & + icepack_write_parameters, & + icepack_configure, & + icepack_query_parameters ! debugging + + use seaice_constants, only: & + seaicePuny, & ! a small number + seaiceBigNumber, & ! a large number + seaiceSecondsPerDay, & ! number of seconds in 1 day + seaiceDensityIce, & ! density of ice (kg/m^3) + seaiceDensitySnow, & ! density of snow (kg/m^3) + seaiceDensitySeaWater, & ! density of seawater (kg/m^3) + seaiceDensityFreshwater, & ! density of freshwater (kg/m^3) + seaiceFreshIceSpecificHeat, & ! specific heat of fresh ice (J/kg/K) + seaiceWaterVaporSpecificHeat, & ! specific heat of water vapor (J/kg/K) + seaiceAirSpecificHeat, & ! specific heat of air (J/kg/K) + seaiceSeaWaterSpecificHeat, & ! specific heat of ocn (J/kg/K) + seaiceLatentHeatVaporization, & ! latent heat, vaporization freshwater (J/kg) + seaiceZvir, & ! rh2o/rair - 1.0 + seaiceLatentHeatSublimation, & ! latent heat, sublimation freshwater (J/kg) + seaiceLatentHeatMelting, & ! latent heat of melting of fresh ice (J/kg) + seaiceIceSurfaceMeltingTemperature, & ! melting temp. ice top surface (C) + seaiceSnowSurfaceMeltingTemperature, & ! melting temp. snow top surface (C) + seaiceStefanBoltzmann, & ! J m-2 K-4 s-1 + seaiceIceSnowEmissivity, & ! emissivity of snow and ice + seaiceSnowSurfaceScatteringLayer, & ! snow surface scattering layer thickness (m) + seaiceStabilityReferenceHeight, & ! stability reference height (m) + seaiceFreshWaterFreezingPoint, & ! freezing temp of fresh ice (K) + seaiceIceSurfaceRoughness, & ! ice surface roughness (m) + seaiceVonKarmanConstant, & ! Von Karman constant + seaiceOceanAlbedo, & ! Ocean albedo + seaiceReferenceSalinity, & ! ice reference salinity (ppt) + seaiceMaximumSalinity, & ! ice maximum salinity (ppt) + seaiceMeltingTemperatureDepression, & ! melting temperature depression factor (C/ppt) + seaiceFrazilSalinityReduction, & ! bulk salinity reduction of newly formed frazil (ppt) + seaiceFrazilIcePorosity, & ! initial liquid fraction of frazil + seaicePi, & ! pi + seaiceGravity, & ! gravitational acceleration (m/s^2) + seaiceSnowPatchiness, & ! snow patchiness parameter + seaiceIceStrengthConstantHiblerP, & ! P* constant in Hibler strength formulation + seaiceIceStrengthConstantHiblerC, & ! C* constant in Hibler strength formulation + skeletalLayerThickness, & ! skeletal layer thickness + gramsCarbonPerMolCarbon, & ! grams carbon per mol carbon + seaiceSnowMinimumDensity, & ! minimum snow density (kg/m^3) + seaiceBrineDynamicViscosity, & ! dynamic viscosity of brine (kg/m/s) + seaiceFreezingTemperatureConstant, &! constant freezing temp of seawater (C) + seaiceExtinctionCoef, & ! vis extnctn coef in ice, wvlngth<700nm (1/m) + seaiceFreshIceConductivity, & ! thermal conductivity of fresh ice(W/m/deg) + seaiceSnowMinimumThickness, & ! min snow thickness for computing zTsn (m) + seaiceFrazilMinimumThickness, & ! min thickness of new frazil ice + seaiceAlbedoWtVisibleDirect, & ! visible, direct + seaiceAlbedoWtNearIRDirect, & ! near IR, direct + seaiceAlbedoWtVisibleDiffuse, & ! visible, diffuse + seaiceAlbedoWtNearIRDiffuse, & ! near IR, diffuse + seaiceQsatQiceConstant, & ! constant for saturation humidity over ice + seaiceQsatTiceConstant, & ! constant for saturation humidity over ice + seaiceQsatQocnConstant, & ! constant for saturation humidity over ocean + seaiceQsatTocnConstant ! constant for saturation humidity over ocean type(domain_type), intent(inout) :: & domain + type(MPAS_pool_type), pointer :: & + snow + character(len=strKIND), pointer :: & config_thermodynamics_type, & config_heat_conductivity_type, & @@ -10046,13 +10117,17 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove config_itd_conversion_type, & config_category_bounds_type, & config_pond_refreezing_type, & + config_salt_flux_coupling_type, & config_ocean_heat_transfer_type, & + config_frazil_coupling_type, & config_sea_freezing_temperature_type, & config_skeletal_bgc_flux_type, & config_snow_redistribution_scheme logical, pointer :: & + config_use_snicar_ad, & config_calc_surface_temperature, & + config_update_ocean_fluxes, & config_use_form_drag, & config_use_high_frequency_coupling, & config_use_ocean_mixed_layer, & @@ -10062,10 +10137,12 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove config_use_vertical_biochemistry, & config_use_shortwave_bioabsorption, & config_use_skeletal_biochemistry, & - config_use_vertical_zsalinity, & config_use_modal_aerosols, & - config_use_snicar_ad, & - config_use_snow_liquid_ponds + config_use_macromolecules, & + config_do_restart_bgc, & + config_use_snow_liquid_ponds, & + config_use_snow_grain_radius, & + config_use_shortwave_redistribution real(kind=RKIND), pointer :: & config_min_friction_velocity, & @@ -10076,15 +10153,21 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove config_rapid_mode_aspect_ratio, & config_slow_mode_drainage_strength, & config_slow_mode_critical_porosity, & + config_macro_drainage_timescale, & config_congelation_ice_porosity, & +! config_frazil_ice_porosity, & +! config_frazil_salinity_reduction, & config_visible_ice_albedo, & config_infrared_ice_albedo, & config_visible_snow_albedo, & config_infrared_snow_albedo, & config_variable_albedo_thickness_limit, & +! config_snow_surface_scattering_layer_depth, & config_ice_shortwave_tuning_parameter, & config_pond_shortwave_tuning_parameter, & config_snow_shortwave_tuning_parameter, & + config_shortwave_redistribution_fraction, & + config_shortwave_redistribution_threshold, & config_temp_change_snow_grain_radius_change, & config_max_melting_snow_grain_radius, & config_algae_absorption_coefficient, & @@ -10102,8 +10185,6 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove config_biogrid_top_molecular_sublayer, & config_new_ice_fraction_biotracer, & config_fraction_biotracer_in_frazil, & - config_zsalinity_molecular_sublayer, & - config_zsalinity_gravity_drainage_scale, & config_snow_porosity_at_ice_surface, & config_ratio_Si_to_N_diatoms, & config_ratio_Si_to_N_small_plankton, & @@ -10228,13 +10309,40 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove config_snow_redistribution_factor, & config_max_dry_snow_radius + real(kind=RKIND), dimension(:,:,:), pointer :: & + snowEmpiricalGrowthParameterTau, & + snowEmpiricalGrowthParameterKappa, & + snowPropertyRate + integer, pointer :: & - config_boundary_layer_iteration_number + config_boundary_layer_iteration_number, & + nGrainAgingTemperature, & + nGrainAgingTempGradient, & + nGrainAgingSnowDensity + + integer :: & + config_thermodynamics_type_int, & + config_ice_strength_formulation_int, & + config_ridging_participation_function_int, & + config_ridging_redistribution_function_int, & + config_itd_conversion_type_int, & + config_category_bounds_type_int + + character(len=strKIND) :: tmp_config_shortwave_type + character(len=strKIND) :: tmp_config_snw_ssp_table + character(len=strKIND) :: snw_aging_table = 'snicar' + + ! debugging + integer :: itmp1, itmp2 + real(kind=RKIND) :: rtmp1, rtmp2 + character(len=strKIND) :: ctmp1, ctmp2 call MPAS_pool_get_config(domain % configs, "config_thermodynamics_type", config_thermodynamics_type) call MPAS_pool_get_config(domain % configs, "config_heat_conductivity_type", config_heat_conductivity_type) call MPAS_pool_get_config(domain % configs, "config_ocean_heat_transfer_type", config_ocean_heat_transfer_type) call MPAS_pool_get_config(domain % configs, "config_calc_surface_temperature", config_calc_surface_temperature) + call MPAS_pool_get_config(domain % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes) + call MPAS_pool_get_config(domain % configs, "config_frazil_coupling_type", config_frazil_coupling_type) call MPAS_pool_get_config(domain % configs, "config_min_friction_velocity", config_min_friction_velocity) call MPAS_pool_get_config(domain % configs, "config_ice_ocean_drag_coefficient", config_ice_ocean_drag_coefficient) call MPAS_pool_get_config(domain % configs, "config_snow_thermal_conductivity", config_snow_thermal_conductivity) @@ -10243,7 +10351,10 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove call MPAS_pool_get_config(domain % configs, "config_rapid_mode_aspect_ratio", config_rapid_mode_aspect_ratio) call MPAS_pool_get_config(domain % configs, "config_slow_mode_drainage_strength", config_slow_mode_drainage_strength) call MPAS_pool_get_config(domain % configs, "config_slow_mode_critical_porosity", config_slow_mode_critical_porosity) + call MPAS_pool_get_config(domain % configs, "config_macro_drainage_timescale", config_macro_drainage_timescale) call MPAS_pool_get_config(domain % configs, "config_congelation_ice_porosity", config_congelation_ice_porosity) +! call MPAS_pool_get_config(domain % configs, "config_frazil_ice_porosity", config_frazil_ice_porosity) +! call MPAS_pool_get_config(domain % configs, "config_frazil_salinity_reduction", config_frazil_salinity_reduction) call MPAS_pool_get_config(domain % configs, "config_shortwave_type", config_shortwave_type) call MPAS_pool_get_config(domain % configs, "config_use_snicar_ad", config_use_snicar_ad) call MPAS_pool_get_config(domain % configs, "config_albedo_type", config_albedo_type) @@ -10252,9 +10363,13 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove call MPAS_pool_get_config(domain % configs, "config_visible_snow_albedo", config_visible_snow_albedo) call MPAS_pool_get_config(domain % configs, "config_infrared_snow_albedo", config_infrared_snow_albedo) call MPAS_pool_get_config(domain % configs, "config_variable_albedo_thickness_limit", config_variable_albedo_thickness_limit) +! call MPAS_pool_get_config(domain % configs, "config_snow_surface_scattering_layer_depth", config_snow_surface_scattering_layer_depth) call MPAS_pool_get_config(domain % configs, "config_ice_shortwave_tuning_parameter", config_ice_shortwave_tuning_parameter) call MPAS_pool_get_config(domain % configs, "config_pond_shortwave_tuning_parameter", config_pond_shortwave_tuning_parameter) call MPAS_pool_get_config(domain % configs, "config_snow_shortwave_tuning_parameter", config_snow_shortwave_tuning_parameter) + call MPAS_pool_get_config(domain % configs, "config_use_shortwave_redistribution", config_use_shortwave_redistribution) + call MPAS_pool_get_config(domain % configs, "config_shortwave_redistribution_fraction", config_shortwave_redistribution_fraction) + call MPAS_pool_get_config(domain % configs, "config_shortwave_redistribution_threshold", config_shortwave_redistribution_threshold) call MPAS_pool_get_config(domain % configs, "config_temp_change_snow_grain_radius_change", & config_temp_change_snow_grain_radius_change) call MPAS_pool_get_config(domain % configs, "config_max_melting_snow_grain_radius", config_max_melting_snow_grain_radius) @@ -10275,6 +10390,7 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove call MPAS_pool_get_config(domain % configs, "config_category_bounds_type", config_category_bounds_type) call MPAS_pool_get_config(domain % configs, "config_snow_to_ice_transition_depth", config_snow_to_ice_transition_depth) call MPAS_pool_get_config(domain % configs, "config_pond_refreezing_type", config_pond_refreezing_type) + call MPAS_pool_get_config(domain % configs, "config_salt_flux_coupling_type", config_salt_flux_coupling_type) call MPAS_pool_get_config(domain % configs, "config_pond_flushing_factor", config_pond_flushing_factor) call MPAS_pool_get_config(domain % configs, "config_min_meltwater_retained_fraction", config_min_meltwater_retained_fraction) call MPAS_pool_get_config(domain % configs, "config_max_meltwater_retained_fraction", config_max_meltwater_retained_fraction) @@ -10288,17 +10404,16 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove call MPAS_pool_get_config(domain % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols", config_use_modal_aerosols) + call MPAS_pool_get_config(domain % configs, "config_use_macromolecules", config_use_macromolecules) + call MPAS_pool_get_config(domain % configs, "config_do_restart_bgc", config_do_restart_bgc) call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) - call MPAS_pool_get_config(domain % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) call MPAS_pool_get_config(domain % configs, "config_biogrid_bottom_molecular_sublayer", & config_biogrid_bottom_molecular_sublayer) call MPAS_pool_get_config(domain % configs, "config_bio_gravity_drainage_length_scale", & config_bio_gravity_drainage_length_scale) call MPAS_pool_get_config(domain % configs, "config_biogrid_top_molecular_sublayer", config_biogrid_top_molecular_sublayer) - call MPAS_pool_get_config(domain % configs, "config_zsalinity_gravity_drainage_scale", config_zsalinity_gravity_drainage_scale) call MPAS_pool_get_config(domain % configs, "config_new_ice_fraction_biotracer", config_new_ice_fraction_biotracer) call MPAS_pool_get_config(domain % configs, "config_fraction_biotracer_in_frazil", config_fraction_biotracer_in_frazil) - call MPAS_pool_get_config(domain % configs, "config_zsalinity_molecular_sublayer", config_zsalinity_molecular_sublayer) call MPAS_pool_get_config(domain % configs, "config_snow_porosity_at_ice_surface", config_snow_porosity_at_ice_surface) call MPAS_pool_get_config(domain % configs, "config_ratio_Si_to_N_diatoms", config_ratio_Si_to_N_diatoms) call MPAS_pool_get_config(domain % configs, "config_ratio_Si_to_N_small_plankton", config_ratio_Si_to_N_small_plankton) @@ -10433,1534 +10548,14 @@ subroutine init_column_package_configs(domain) !colpkg routine - remove call MPAS_pool_get_config(domain % configs, "config_wind_compaction_factor", config_wind_compaction_factor) call MPAS_pool_get_config(domain % configs, "config_snow_redistribution_factor", config_snow_redistribution_factor) call MPAS_pool_get_config(domain % configs, "config_max_dry_snow_radius", config_max_dry_snow_radius) - - call colpkg_init_parameters(& - config_cice_int("config_thermodynamics_type", config_thermodynamics_type), & - config_heat_conductivity_type, & - config_ocean_heat_transfer_type, & - config_calc_surface_temperature, & - config_min_friction_velocity, & - config_ice_ocean_drag_coefficient, & - config_snow_thermal_conductivity, & - config_rapid_mode_channel_radius, & - config_rapid_model_critical_Ra, & - config_rapid_mode_aspect_ratio, & - config_slow_mode_drainage_strength, & - config_slow_mode_critical_porosity, & - config_congelation_ice_porosity, & - config_shortwave_type, & - config_use_snicar_ad, & - config_albedo_type, & - config_visible_ice_albedo, & - config_infrared_ice_albedo, & - config_visible_snow_albedo, & - config_infrared_snow_albedo, & - config_variable_albedo_thickness_limit, & - config_ice_shortwave_tuning_parameter, & - config_pond_shortwave_tuning_parameter, & - config_snow_shortwave_tuning_parameter, & - config_temp_change_snow_grain_radius_change, & - config_max_melting_snow_grain_radius, & - config_algae_absorption_coefficient, & - config_cice_int("config_ice_strength_formulation", config_ice_strength_formulation), & - config_cice_int("config_ridging_participation_function", config_ridging_participation_function), & - config_cice_int("config_ridging_redistribution_function", config_ridging_redistribution_function), & - config_ridging_efolding_scale, & - config_ratio_ridging_work_to_PE, & - config_atmos_boundary_method, & - config_calc_surface_stresses, & - config_use_form_drag, & - config_use_high_frequency_coupling, & - config_boundary_layer_iteration_number, & - config_use_ocean_mixed_layer, & - config_sea_freezing_temperature_type, & - config_cice_int("config_itd_conversion_type", config_itd_conversion_type), & - config_cice_int("config_category_bounds_type", config_category_bounds_type), & - config_snow_to_ice_transition_depth, & - config_pond_refreezing_type, & - config_pond_flushing_factor, & - config_min_meltwater_retained_fraction, & - config_max_meltwater_retained_fraction, & - config_pond_depth_to_fraction_ratio, & - config_snow_on_pond_ice_tapering_parameter, & - config_critical_pond_ice_thickness, & - config_skeletal_bgc_flux_type, & - config_use_vertical_tracers, & - config_scale_initial_vertical_bgc, & - config_use_vertical_biochemistry, & - config_use_shortwave_bioabsorption, & - config_use_modal_aerosols, & - config_use_skeletal_biochemistry, & - config_use_vertical_zsalinity, & - config_biogrid_bottom_molecular_sublayer, & - config_bio_gravity_drainage_length_scale, & - config_biogrid_top_molecular_sublayer, & - config_new_ice_fraction_biotracer, & - config_fraction_biotracer_in_frazil, & - config_zsalinity_molecular_sublayer, & - config_zsalinity_gravity_drainage_scale, & - config_snow_porosity_at_ice_surface, & - config_ratio_Si_to_N_diatoms, & - config_ratio_Si_to_N_small_plankton, & - config_ratio_Si_to_N_phaeocystis, & - config_ratio_S_to_N_diatoms, & - config_ratio_S_to_N_small_plankton, & - config_ratio_S_to_N_phaeocystis, & - config_ratio_Fe_to_C_diatoms, & - config_ratio_Fe_to_C_small_plankton, & - config_ratio_Fe_to_C_phaeocystis, & - config_ratio_Fe_to_N_diatoms, & - config_ratio_Fe_to_N_small_plankton, & - config_ratio_Fe_to_N_phaeocystis, & - config_ratio_Fe_to_DON, & - config_ratio_Fe_to_DOC_saccharids, & - config_ratio_Fe_to_DOC_lipids, & - config_respiration_fraction_of_growth, & - config_rapid_mobile_to_stationary_time, & - config_long_mobile_to_stationary_time, & - config_algal_maximum_velocity, & - config_ratio_Fe_to_dust, & - config_solubility_of_Fe_in_dust, & - config_chla_absorptivity_of_diatoms, & - config_chla_absorptivity_of_small_plankton, & - config_chla_absorptivity_of_phaeocystis, & - config_light_attenuation_diatoms, & - config_light_attenuation_small_plankton, & - config_light_attenuation_phaeocystis, & - config_light_inhibition_diatoms, & - config_light_inhibition_small_plankton, & - config_light_inhibition_phaeocystis, & - config_maximum_growth_rate_diatoms, & - config_maximum_growth_rate_small_plankton, & - config_maximum_growth_rate_phaeocystis, & - config_temperature_growth_diatoms, & - config_temperature_growth_small_plankton, & - config_temperature_growth_phaeocystis, & - config_grazed_fraction_diatoms, & - config_grazed_fraction_small_plankton, & - config_grazed_fraction_phaeocystis, & - config_mortality_diatoms, & - config_mortality_small_plankton, & - config_mortality_phaeocystis, & - config_temperature_mortality_diatoms, & - config_temperature_mortality_small_plankton, & - config_temperature_mortality_phaeocystis, & - config_exudation_diatoms, & - config_exudation_small_plankton, & - config_exudation_phaeocystis, & - config_nitrate_saturation_diatoms, & - config_nitrate_saturation_small_plankton, & - config_nitrate_saturation_phaeocystis, & - config_ammonium_saturation_diatoms, & - config_ammonium_saturation_small_plankton, & - config_ammonium_saturation_phaeocystis, & - config_silicate_saturation_diatoms, & - config_silicate_saturation_small_plankton, & - config_silicate_saturation_phaeocystis, & - config_iron_saturation_diatoms, & - config_iron_saturation_small_plankton, & - config_iron_saturation_phaeocystis, & - config_fraction_spilled_to_DON, & - config_degredation_of_DON, & - config_fraction_DON_ammonium, & - config_fraction_loss_to_saccharids, & - config_fraction_loss_to_lipids, & - config_fraction_exudation_to_saccharids, & - config_fraction_exudation_to_lipids, & - config_remineralization_saccharids, & - config_remineralization_lipids, & - config_maximum_brine_temperature, & - config_salinity_dependence_of_growth, & - config_minimum_optical_depth, & - config_slopped_grazing_fraction, & - config_excreted_fraction, & - config_fraction_mortality_to_ammonium, & - config_fraction_iron_remineralized, & - config_nitrification_rate, & - config_desorption_loss_particulate_iron, & - config_maximum_loss_fraction, & - config_maximum_ratio_iron_to_saccharids, & - config_respiration_loss_to_DMSPd, & - config_DMSP_to_DMS_conversion_fraction, & - config_DMSP_to_DMS_conversion_time, & - config_DMS_oxidation_time, & - config_mobility_type_diatoms, & - config_mobility_type_small_plankton, & - config_mobility_type_phaeocystis, & - config_mobility_type_nitrate, & - config_mobility_type_ammonium, & - config_mobility_type_silicate, & - config_mobility_type_DMSPp, & - config_mobility_type_DMSPd, & - config_mobility_type_humics, & - config_mobility_type_saccharids, & - config_mobility_type_lipids, & - config_mobility_type_inorganic_carbon, & - config_mobility_type_proteins, & - config_mobility_type_dissolved_iron, & - config_mobility_type_particulate_iron, & - config_mobility_type_black_carbon1, & - config_mobility_type_black_carbon2, & - config_mobility_type_dust1, & - config_mobility_type_dust2, & - config_mobility_type_dust3, & - config_mobility_type_dust4, & - config_ratio_C_to_N_diatoms, & - config_ratio_C_to_N_small_plankton, & - config_ratio_C_to_N_phaeocystis, & - config_ratio_chla_to_N_diatoms, & - config_ratio_chla_to_N_small_plankton, & - config_ratio_chla_to_N_phaeocystis, & - config_scales_absorption_diatoms, & - config_scales_absorption_small_plankton, & - config_scales_absorption_phaeocystis, & - config_ratio_C_to_N_proteins, & - config_snow_redistribution_scheme, & - config_use_snow_liquid_ponds, & - config_fallen_snow_radius, & - config_max_dry_snow_radius, & - config_new_snow_density, & - config_max_snow_density, & - config_minimum_wind_compaction, & - config_wind_compaction_factor, & - config_snow_redistribution_factor) - - !----------------------------------------------------------------------- - ! Parameters for thermodynamics - !----------------------------------------------------------------------- - - ! ktherm: - ! type of thermodynamics - ! 1 = Bitz and Lipscomb 1999 - ! 2 = mushy layer theory - !ktherm = config_cice_int("config_thermodynamics_type", config_thermodynamics_type) - - ! conduct: - ! 'MU71' or 'bubbly' - !conduct = config_heat_conductivity_type - - ! calc_Tsfc: - ! if true, calculate surface temperature - ! if false, Tsfc is computed elsewhere and - ! atmos-ice fluxes are provided to CICE - !calc_Tsfc = config_calc_surface_temperature - - ! ustar_min: - ! minimum friction velocity for ice-ocean heat flux - !ustar_min = config_min_friction_velocity - - ! mushy thermodynamics: - - ! a_rapid_mode: - ! channel radius for rapid drainage mode (m) - !a_rapid_mode = config_rapid_mode_channel_radius - - ! Rac_rapid_mode: - ! critical rayleigh number for rapid drainage mode - !Rac_rapid_mode = config_rapid_model_critical_Ra - - ! aspect_rapid_mode: - ! aspect ratio for rapid drainage mode (larger=wider) - !aspect_rapid_mode = config_rapid_mode_aspect_ratio - - ! dSdt_slow_mode: - ! slow mode drainage strength (m s-1 K-1) - !dSdt_slow_mode = config_slow_mode_drainage_strength - - ! phi_c_slow_mode: - ! liquid fraction porosity cutoff for slow mode - !phi_c_slow_mode = config_slow_mode_critical_porosity - - ! phi_i_mushy: - ! liquid fraction of congelation ice - !phi_i_mushy = config_congelation_ice_porosity - - !----------------------------------------------------------------------- - ! Parameters for radiation - !----------------------------------------------------------------------- - - ! shortwave: - ! shortwave method, 'default' ('ccsm3') or 'dEdd' - !shortwave = config_shortwave_type - - ! albedo_type: - ! albedo parameterization, 'default' ('ccsm3') or 'constant' - ! shortwave='dEdd' overrides this parameter - !albedo_type = config_albedo_type - - ! baseline albedos for ccsm3 shortwave, set in namelist - - ! albicev: - ! visible ice albedo for h > ahmax - !albicev = config_visible_ice_albedo - - ! albicei: - ! near-ir ice albedo for h > ahmax - !albicei = config_infrared_ice_albedo - - ! albsnowv: - ! cold snow albedo, visible - !albsnowv = config_visible_snow_albedo - - ! albsnowi: - ! cold snow albedo, near IR - !albsnowi = config_infrared_snow_albedo - - ! ahmax: - ! thickness above which ice albedo is constant (m) - !ahmax = config_variable_albedo_thickness_limit - - ! dEdd tuning parameters, set in namelist - - ! R_ice: - ! sea ice tuning parameter; +1 > 1sig increase in albedo - !R_ice = config_ice_shortwave_tuning_parameter - - ! R_pnd: - ! ponded ice tuning parameter; +1 > 1sig increase in albedo - !R_pnd = config_pond_shortwave_tuning_parameter - - ! R_snw: - ! snow tuning parameter; +1 > ~.01 change in broadband albedo - !R_snw = config_snow_shortwave_tuning_parameter - - ! dT_mlt: - ! change in temp for non-melt to melt snow grain radius change (C) - !dT_mlt = config_temp_change_snow_grain_radius_change - - ! rsnw_mlt: - ! maximum melting snow grain radius (10^-6 m) - !rsnw_mlt = config_max_melting_snow_grain_radius - - ! kalg: - ! algae absorption coefficient for 0.5 m thick layer - !kalg = config_algae_absorption_coefficient - - !----------------------------------------------------------------------- - ! Parameters for ridging and strength - !----------------------------------------------------------------------- - - ! kstrength: - ! 0 for simple Hibler (1979) formulation - ! 1 for Rothrock (1975) pressure formulation - !kstrength = config_cice_int("config_ice_strength_formulation", config_ice_strength_formulation) - - ! krdg_partic: - ! 0 for Thorndike et al. (1975) formulation - ! 1 for exponential participation function - !krdg_partic = config_cice_int("config_ridging_participation_function", config_ridging_participation_function) - - ! krdg_redist: - ! 0 for Hibler (1980) formulation - ! 1 for exponential redistribution function - !krdg_redist = config_cice_int("config_ridging_redistribution_function", config_ridging_redistribution_function) - - ! mu_rdg: - ! gives e-folding scale of ridged ice (m^.5) - ! (krdg_redist = 1) - !mu_rdg = config_ridging_efolding_scale - - ! Cf - ! ratio of ridging work to PE change in ridging (kstrength = 1) - !Cf = config_ratio_ridging_work_to_PE - - !----------------------------------------------------------------------- - ! Parameters for atmosphere - !----------------------------------------------------------------------- - - ! atmbndy: - ! atmo boundary method, 'default' ('ccsm3') or 'constant' - !atmbndy = config_atmos_boundary_method - - ! calc_strair: - ! if true, calculate wind stress components - !calc_strair = config_calc_surface_stresses - - ! formdrag: - ! if true, calculate form drag - !formdrag = config_use_form_drag - - ! highfreq: - ! if true, use high frequency coupling - !highfreq = config_use_high_frequency_coupling - - ! natmiter: - ! number of iterations for boundary layer calculations - !natmiter = config_boundary_layer_iteration_number - - !----------------------------------------------------------------------- - ! Parameters for ocean - !----------------------------------------------------------------------- - - ! oceanmixed_ice: - ! if true, use ocean mixed layer - !oceanmixed_ice = config_use_ocean_mixed_layer - - ! fbot_xfer_type: - ! transfer coefficient type for ice-ocean heat flux - !fbot_xfer_type = config_ocean_heat_transfer_type - - ! tfrz_option: - ! form of ocean freezing temperature - ! 'minus1p8' = -1.8 C - ! 'linear_salt' = -depressT * sss - ! 'mushy' conforms with ktherm=2 - !tfrz_option = config_sea_freezing_temperature_type - - !----------------------------------------------------------------------- - ! Parameters for the ice thickness distribution - !----------------------------------------------------------------------- - - ! kitd: - ! type of itd conversions - ! 0 = delta function - ! 1 = linear remap - !kitd = config_cice_int("config_itd_conversion_type", config_itd_conversion_type) - - ! kcatbound: - ! 0 = old category boundary formula - ! 1 = new formula giving round numbers - ! 2 = WMO standard - ! 3 = asymptotic formula - !kcatbound = config_cice_int("config_category_bounds_type", config_category_bounds_type) - - !----------------------------------------------------------------------- - ! Parameters for melt ponds - !----------------------------------------------------------------------- - - ! hs0: - ! snow depth for transition to bare sea ice (m) - !hs0 = config_snow_to_ice_transition_depth - - ! level-ice ponds - - ! frzpnd: - ! pond refreezing parameterization - !frzpnd = config_pond_refreezing_type - - ! dpscale: - ! alters e-folding time scale for flushing with BL99 thermodynamics - !dpscale = config_pond_flushing_factor - - ! rfracmin: - ! minimum retained fraction of meltwater - !rfracmin = config_min_meltwater_retained_fraction - - ! rfracmax: - ! maximum retained fraction of meltwater - !rfracmax = config_max_meltwater_retained_fraction - - ! pndaspect: - ! ratio of pond depth to pond fraction - !pndaspect = config_pond_depth_to_fraction_ratio - - ! hs1: - ! tapering parameter for snow on pond ice - !hs1 = config_snow_on_pond_ice_tapering_parameter - - ! topo ponds - - ! hp1 - ! critical parameter for pond ice thickness - !hp1 = config_critical_pond_ice_thickness - - !----------------------------------------------------------------------- - ! Parameters for biogeochemistry - !----------------------------------------------------------------------- - - ! bgc_flux_type: - ! bgc_flux_type = config_skeletal_bgc_flux_type - - ! z_tracers: - ! if .true., bgc or aerosol tracers are vertically resolved - !z_tracers = config_use_vertical_tracers - - ! scale_bgc: - ! if .true., initialize bgc tracers proportionally with salinity - !scale_bgc = config_scale_initial_vertical_bgc - - ! solve_zbgc: - ! if .true., solve vertical biochemistry portion of code - !solve_zbgc = config_use_vertical_biochemistry - - ! dEdd_algae: - ! if .true., algal absorption of Shortwave is computed in the - !dEdd_algae = config_use_shortwave_bioabsorption - - ! skl_bgc: - ! if true, solve skeletal biochemistry - !skl_bgc = config_use_skeletal_biochemistry - -! zsalinity has been deprecated -! ! solve_zsal: -! ! if true, update salinity profile from solve_S_dt -! !solve_zsal = config_use_vertical_zsalinity - - ! modal_aero: - ! if true, use modal aerosal optical properties - ! only for use with tr_aero or tr_zaero - !modal_aero = config_use_shortwave_bioabsorption - - ! grid_o: - ! for bottom flux - !grid_o = config_biogrid_bottom_molecular_sublayer - - ! l_sk: - ! characteristic diffusive scale (zsalinity) (m) - !l_sk =config_bio_gravity_drainage_length_scale - - ! grid_o_t: - ! top grid point length scale - !grid_o_t = config_biogrid_top_molecular_sublayer - - ! phi_snow: - ! porosity of snow - !phi_snow = config_snow_porosity_at_ice_surface - - ! initbio_frac: - ! fraction of ocean tracer concentration used to initialize tracer - !initbio_frac = config_new_ice_fraction_biotracer - - ! frazil_scav: - ! multiple of ocean tracer concentration due to frazil scavenging - !frazil_scav = config_fraction_biotracer_in_frazil - - ! ratio_Si2N_diatoms: - ! ratio of algal Silicate to Nitrate (mol/mol) - ! ratio_Si2N_diatoms = config_ratio_Si_to_N_diatoms - - ! ratio_Si2N_sp: - ! ratio of algal Silicate to Nitrogen (mol/mol) - ! ratio_Si2N_sp = config_ratio_Si_to_N_small_plankton - - ! ratio_Si2N_phaeo: - ! ratio of algal Silicate to Nitrogen (mol/mol) - ! ratio_Si2N_phaeo = config_ratio_Si_to_N_phaeocystis - - ! ratio_S2N_diatoms: - ! ratio of algal Sulphur to Nitrogen (mol/mol) - ! ratio_S2N_diatoms = config_ratio_S_to_N_diatoms - - ! ratio_S2N_sp: - ! ratio of algal Sulphur to Nitrogen (mol/mol) - ! ratio_S2N_sp = config_ratio_S_to_N_small_plankton - - ! ratio_S2N_phaeo: - ! ratio of algal Sulphur to Nitrogen (mol/mol) - ! ratio_S2N_phaeo = config_ratio_S_to_N_phaeocystis - - ! ratio_Fe2C_diatoms: - ! ratio of algal iron to carbon (umol/mol) - ! ratio_Fe2C_diatoms = config_ratio_Fe_to_C_diatoms - - ! ratio_Fe2C_sp: - ! ratio of algal iron to carbon (umol/mol) - ! ratio_Fe2C_sp = config_ratio_Fe_to_C_small_plankton - - ! ratio_Fe2C_phaeo: - ! ratio of algal iron to carbon (umol/mol) - ! ratio_Fe2C_phaeo = config_ratio_Fe_to_C_phaeocystis - - ! ratio_Fe2N_diatoms: - ! ratio of algal iron to nitrogen (umol/mol) - ! ratio_Fe2N_diatoms = config_ratio_Fe_to_N_diatoms - - ! ratio_Fe2N_sp: - ! ratio of algal iron to nitrogen (umol/mol) - ! ratio_Fe2N_sp = config_ratio_Fe_to_N_small_plankton - - ! ratio_Fe2N_phaeo: - ! ratio of algal iron to nitrogen (umol/mol) - ! ratio_Fe2N_phaeo = config_ratio_Fe_to_N_phaeocystis - - ! ratio_Fe2DON: - ! ratio of iron to nitrogen of DON (nmol/umol) - ! ratio_Fe2DON = config_ratio_Fe_to_DON - - ! ratio_Fe2DOC_s: - ! ratio of iron to carbon of DOC (nmol/umol) saccharids - ! ratio_Fe2DOC_s = config_ratio_Fe_to_DOC_saccharids - - ! ratio_Fe2DOC_l: - ! ratio of iron to carbon of DOC (nmol/umol) lipids - ! ratio_Fe2DOC_l = config_ratio_Fe_to_DOC_lipids - - ! fr_resp: - ! fraction of algal growth lost due to respiration - ! fr_resp = config_respiration_fraction_of_growth - - ! tau_min: - ! rapid mobile to stationary exchanges (s) = 1.5 hours - ! tau_min = config_rapid_mobile_to_stationary_time - - ! tau_max: - ! long time mobile to stationary exchanges (s) = 2 days - ! tau_max = config_long_mobile_to_stationary_time - - ! algal_vel: - ! 0.5 cm/d(m/s) Lavoie 2005 1.5 cm/day - ! algal_vel = config_algal_maximum_velocity - - ! R_dFe2dust: - ! g/g (3.5% content) Tagliabue 2009 - ! R_dFe2dust = config_ratio_Fe_to_dust - - ! dustFe_sol; - ! solubility fraction - ! dustFe_sol = config_solubility_of_Fe_in_dust - - ! chlabs_diatoms: - ! chl absorption (1/m/(mg/m^3)) - ! chlabs_diatoms = config_chla_absorptivity_of_diatoms - - ! chlabs_sp: - ! chl absorption (1/m/(mg/m^3)) - ! chlabs_sp = config_chla_absorptivity_of_small_plankton - - ! chlabs_phaeo: - ! chl absorption (1/m/(mg/m^3)) - ! chlabs_phaeo = config_chla_absorptivity_of_phaeocystis - - ! alpha2max_low_diatoms: - ! light limitation diatoms (1/(W/m^2)) - ! alpha2max_low_diatoms = config_light_attenuation_diatoms - - ! alpha2max_low_sp: - ! light limitation small plankton (1/(W/m^2)) - ! alpha2max_low_sp = config_light_attenuation_small_plankton - - ! alpha2max_low_phaeo: - ! light limitation phaeocystis (1/(W/m^2)) - ! alpha2max_low_phaeo = config_light_attenuation_phaeocystis - - ! beta2max_diatoms: - ! light inhibition diatoms(1/(W/m^2)) - ! beta2max_diatoms = config_light_inhibition_diatoms - - ! beta2max_sp: - ! light inhibition small plankton(1/(W/m^2)) - ! beta2max_sp = config_light_inhibition_small_plankton - - ! beta2max_phaeo: - ! light inhibition phaeocystis (1/(W/m^2)) - ! beta2max_phaeo = config_light_inhibition_phaeocystis - - ! mu_max_diatoms: - ! maximum growth rate diatoms (1/day) - ! mu_max_diatoms = config_maximum_growth_rate_diatoms - - ! mu_max_sp: - ! maximum growth rate small plankton (1/day) - ! mu_max_sp = config_maximum_growth_rate_small plankton - - ! mu_max_phaeo: - ! maximum growth rate phaeocystis (1/day) - ! mu_max_phaeo = config_maximum_growth_rate_phaeocystis - - ! grow_Tdep_sp: - ! Temperature dependence of growth small plankton (1/C) - ! grow_Tdep_sp = config_temperature_growth_small_plankton - - ! grow_Tdep_phaeo: - ! Temperature dependence of growth phaeocystis (1/C) - ! grow_Tdep_phaeo = config_temperature_growth_phaeocystis - - ! fr_graze_diatoms: - ! Fraction grazed diatoms - ! fr_graze_diatoms = config_grazed_fraction_diatoms - - ! fr_graze_sp: - ! Fraction grazed small_plankton - ! fr_graze_sp = config_grazed_fraction_small_plankton - - ! fr_graze_phaeo: - ! Fraction grazed phaeocystis - ! fr_graze_phaeo = config_grazed_fraction_phaeocystis - - ! mort_pre_diatoms: - ! Mortality diatoms (1/day) - ! mort_pre_diatoms = config_mortality_diatoms - - ! mort_pre_sp: - ! Mortality small_plankton (1/day) - ! mort_pre_sp = config_mortality_small_plankton - - ! mort_pre_phaeo: - ! Mortality phaeocystis (1/day) - ! mort_pre_phaeo = config_mortality_phaeocystis - - ! mort_Tdep_diatoms: - ! T dependence of mortality diatoms (1/C) - ! mort_Tdep_diatoms = config_temperature_mortality_diatoms - - ! mort_Tdep_sp: - ! T dependence of mortality small plankton (1/C) - ! mort_Tdep_sp = config_temperature_mortality_small_plankton - - ! mort_Tdep_phaeo: - ! T dependence of mortality phaeocystis (1/C) - ! mort_Tdep_phaeo = config_temperature_mortality_phaeocystis - - ! k_exude_diatoms: - ! algal exudation diatoms (1/d) - ! k_exude_diatoms = config_exudation_diatoms - - ! k_exude_sp: - ! algal exudation small_plankton (1/d) - ! k_exude_sp = config_exudation_small_plankton - - ! k_exude_phaeo: - ! algal exudation phaeocystis (1/d) - ! k_exude_phaeo = config_exudation_phaeocystis - - ! K_Nit_diatoms: - ! nitrate half saturation diatoms (mmol/m^3) - ! K_Nit_diatoms = config_nitrate_saturation_diatoms - - ! K_Nit_sp: - ! nitrate half saturation small_plankton (mmol/m^3) - ! K_Nit_sp = config_nitrate_saturation_small_plankton - - ! K_Nit_phaeo: - ! nitrate half saturation phaeocystis (mmol/m^3) - ! K_Nit_phaeocystis = config_nitrate_saturation_phaeocystis - - ! K_Am_diatoms: - ! ammonium half saturation diatoms (mmol/m^3) - ! K_Am_diatoms = config_ammonium_saturation_diatoms - - ! K_Am_sp: - ! ammonium half saturation small_plankton (mmol/m^3) - ! K_Am_sp = config_ammonium_saturation_small_plankton - - ! K_Am_phaeo: - ! ammonium half saturation phaeocystis (mmol/m^3) - ! K_Am_phaeocystis = config_ammonium_saturation_phaeocystis - - ! K_Sil_diatoms: - ! silicate half saturation diatoms (mmol/m^3) - ! K_Sil_diatoms = config_silicate_saturation_diatoms - - ! K_Sil_sp: - ! silicate half saturation small_plankton (mmol/m^3) - ! K_Sil_sp = config_silicate_saturation_small_plankton - - ! K_Sil_phaeo: - ! silicate half saturation phaeocystis (mmol/m^3) - ! K_Sil_phaeocystis = config_silicate_saturation_phaeocystis - - ! K_Fe_diatoms: - ! iron half saturation diatoms (nM) - ! K_Fe_diatoms = config_iron_saturation_diatoms - - ! K_Fe_sp: - ! iron half saturation small_plankton (nM) - ! K_Fe_sp = config_iron_saturation_small_plankton - - ! K_Fe_phaeo: - ! iron half saturation phaeocystis (nM) - ! K_Fe_phaeocystis = config_iron_saturation_phaeocystis - - ! f_don_protein: - ! fraction of spilled grazing to proteins ! - ! f_don_protein = config_fraction_spilled_to_DON - - ! kn_bac_protein: - ! Bacterial degredation of DON (1/d) ! ! - ! kn_bac_protein = config_degredation_of_DON - - ! f_don_Am_protein: - ! fraction of remineralized DON to ammonium ! - ! f_don_Am_protein = config_fraction_DON_ammonium - - ! f_doc_s: - ! fraction of mortality to DOC saccharids - ! f_doc_s = config_fraction_loss_to_saccharids - - ! f_doc_l: - ! fraction of mortality to DOC lipids - ! f_doc_l = config_fraction_loss_to_lipids - - ! f_exude_s: - ! fraction of exudation to DOC saccharids - ! f_exude_s = config_fraction_exudation_to_saccharids - - ! f_exude_l: - ! fraction of exudation to DOC lipids - ! f_exude_l = config_fraction_exudation_to_lipids - - ! k_bac_s: - ! Bacterial degredation of DOC (1/d) saccharids - ! k_bac_s = config_remineralization_saccharids - - ! k_bac_l: - ! Bacterial degredation of DOC (1/d) lipids - ! k_bac_l = config_remineralization_lipids - - ! T_max: - ! maximum temperature (C) - ! T_max = config_maximum_brine_temperature - - ! fsal: - ! Salinity limitation (ppt) - ! fsal = config_salinity_dependence_of_growth - - ! op_dep_min: - ! Light attenuates for optical depths exceeding min - ! op_dep_min = config_minimum_optical_depth - - ! fr_graze_s: - ! fraction of grazing spilled or slopped - ! fr_graze_s = config_slopped_grazing_fraction - - ! fr_graze_e: - ! fraction of assimilation excreted - ! fr_graze_e = config_excreted_fraction - - ! fr_mort2min: - ! fractionation of mortality to Am - ! fr_mort2min = config_fraction_mortality_to_ammonium - - ! fr_dFe: - ! remineralized nitrogen (in units of algal iron) - ! fr_dFe = config_fraction_iron_remineralized - - ! k_nitrif: - ! nitrification rate (1/day) - ! k_nitrif = config_nitrification_rate - - ! t_iron_conv: - ! desorption loss pFe to dFe (day) - ! t_iron_conv = config_desorption_loss_particulate_iron - - ! max_loss: - ! restrict uptake to % of remaining value - ! max_loss = config_maximum_loss_fraction - - ! max_dfe_doc1: - ! max ratio of dFe to saccharides in the ice (nM Fe/muM C) - ! max_dfe_doc1 = config_maximum_ratio_iron_to_saccharids - - ! fr_resp_s: - ! DMSPd fraction of respiration loss as DMSPd - ! fr_resp_s = config_respiration_loss_to_DMSPd - - ! y_sk_DMS: - ! fraction conversion given high yield - ! y_sk_DMS = config_DMSP_to_DMS_conversion_fraction - - ! t_sk_conv: - ! Stefels conversion time (d) - ! t_sk_conv = config_DMSP_to_DMS_conversion_time - - ! t_sk_ox: - ! DMS oxidation time (d) - ! t_sk_ox = config_DMS_oxidation_time - - ! algaltype_diatoms: - ! mobility type diatoms - ! algaltype_diatoms = config_mobility_type_diatoms - - ! algaltype_sp: - ! mobility type small_plankton - ! algaltype_sp = config_mobility_type_small_plankton - - ! algaltype_phaeo: - ! mobility type phaeocystis - ! algaltype_phaeo = config_mobility_type_phaeocystis - - ! nitratetype: - ! mobility type nitrate - ! nitratetype = config_mobility_type_nitrate - - ! ammoniumtype: - ! mobility type ammonium - ! ammoniumtype = config_mobility_type_ammonium - - ! silicatetype: - ! mobility type silicate - ! silicatetype = config_mobility_type_silicate - - ! dmspptype: - ! mobility type DMSPp - ! dmspptype = config_mobility_type_DMSPp - - ! dmspdtype: - ! mobility type DMSPd - ! dmspdtype = config_mobility_type_DMSPd - - ! humicstype: - ! mobility type humics - ! humicstype = config_mobility_type_humics - - ! doctype_s: - ! mobility type sachharids - ! doctype_s = config_mobility_type_saccharids - - ! doctype_l: - ! mobility type lipids - ! doctype_l = config_mobility_type_lipids - - ! dictype_1: - ! mobility type dissolved inorganic carbon - ! dictype_1 = config_mobility_type_inorganic_carbon - - ! dontype_protein: - ! mobility type proteins - ! dontype_protein = config_mobility_type_proteins - - ! fedtype_1: - ! mobility type dissolved iron - ! fedtype_1 = config_mobility_type_dissolved_iron - - ! feptype_1: - ! mobility type particulate iron - ! feptype_1 = config_mobility_type_particulate_iron - - ! zaerotype_bc1: - ! mobility type for black carbon 1 - ! zaerotype_bc1 = config_mobility_type_black_carbon1 - - ! zaerotype_bc2: - ! mobility type for black carbon 2 - ! zaerotype_bc2 = config_mobility_type_black_carbon2 - - ! zaerotype_dust1: - ! mobility type for dust 1 - ! zaerotype_dust1 = config_mobility_type_dust1 - - ! zaerotype_dust2: - ! mobility type for dust 2 - ! zaerotype_dust2 = config_mobility_type_dust2 - - ! zaerotype_dust3: - ! mobility type for dust 3 - ! zaerotype_dust3 = config_mobility_type_dust3 - - ! zaerotype_dust4: - ! mobility type for dust 4 - ! zaerotype_dust4 = config_mobility_type_dust4 - - ! ratio_C2N_diatoms: - ! algal C to N ratio (mol/mol) diatoms - ! ratio_C2N_diatoms = config_ratio_C_to_N_diatoms - - ! ratio_C2N_sp: - ! algal C to N ratio (mol/mol) small_plankton - ! ratio_C2N_sp = config_ratio_C_to_N_small_plankton - - ! ratio_C2N_phaeo: - ! algal C to N ratio (mol/mol) phaeocystis - ! ratio_C2N_phaeo = config_ratio_C_to_N_phaeocystis - - ! ratio_chl2N_diatoms: - ! algal chla to N ratio (mol/mol) diatoms - ! ratio_chl2N_diatoms = config_ratio_chla_to_N_diatoms - - ! ratio_chl2N_sp: - ! algal chla to N ratio (mol/mol) small_plankton - ! ratio_chl2N_sp = config_ratio_chla_to_N_small_plankton - - ! ratio_chl2N_phaeo: - ! algal chla to N ratio (mol/mol) phaeocystis - ! ratio_chl2N_phaeo = config_ratio_chla_to_N_phaeocystis - - ! F_abs_chl_diatoms: - ! scales absorbed radiation for dEdd diatoms - ! F_abs_chl_diatoms = config_scales_absorption_diatoms - - ! F_abs_chl_sp: - ! scales absorbed radiation for dEdd small_plankton - ! F_abs_chl_sp = config_scales_absorption_small_plankton - - ! F_abs_chl_phaeo: - ! scales absorbed radiation for dEdd phaeocystis - ! F_abs_chl_phaeo = config_scales_absorption_phaeocystis - - ! ratio_C2N_proteins: - ! ratio of C to N in proteins (mol/mol) - ! ratio_C2N_proteins = config_ratio_C_to_N_proteins - -! ! grid_oS: -! ! for bottom flux (zsalinity) -! !grid_oS = config_zsalinity_molecular_sublayer - - ! l_skS: -! ! 0.02 characteristic skeletal layer thickness (m) (zsalinity) -! !l_skS = config_zsalinity_gravity_drainage_scale - - !----------------------------------------------------------------------- - ! Parameters for snow - !----------------------------------------------------------------------- - - ! snwredist: - ! snow redistribution type - ! snwredist = config_snow_redistribution_scheme - - ! use_smliq_pnd: - ! convert excess snow liquid to ponds - ! use_smliq_pnd = config_use_snow_liquid_ponds - - ! rsnw_fall: - ! fallen snow grain radius (um) - ! rsnw_fall = config_fallen_snow_radius - - ! rsnw_tmax: - ! maximum dry metamorphism snow grain radius (um) - ! rsnw_tmax = config_max_dry_snow_radius - - ! rhosnew: - ! new snow density (kg/m^3) - ! rhosnew = config_new_snow_density - - ! rhosmax: - ! maximum snow density (kg/m^3) - ! rhosmax = config_max_snow_density - - ! windmin: - ! minimum wind speed to compact snow (m/s) - ! windmin = config_minimum_wind_compaction - - ! snwlvlfac: - ! snow loss factor for wind redistribution - ! snwlvlfac = config_snow_redistribution_factor - - ! drhosdwind: - ! wind compaction factor (kg s/m^4) - ! drhosdwind = config_wind_compaction_factor - - end subroutine init_column_package_configs - -!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -! -! init_icepack_package_configs -! -!> \brief -!> \author Adrian K. Turner, Elizabeth Hunke, Darin Comeau, Nicole Jeffery, Andrew Roberts, Erin Thomas, Jon Wolfe, LANL, Anthony Craig, NOAA (cntr), David Bailey, NCAR -!> \date 2022-2023 -!> \details -!> -! -!----------------------------------------------------------------------- - - subroutine init_icepack_package_configs(domain) - - use icepack_intfc, only: & - icepack_init_parameters, & - icepack_write_parameters, & - icepack_configure, & - icepack_query_parameters ! debugging - - use seaice_constants, only: & - seaicePuny, & ! a small number - seaiceBigNumber, & ! a large number - seaiceSecondsPerDay, & ! number of seconds in 1 day - seaiceDensityIce, & ! density of ice (kg/m^3) - seaiceDensitySnow, & ! density of snow (kg/m^3) - seaiceDensitySeaWater, & ! density of seawater (kg/m^3) - seaiceDensityFreshwater, & ! density of freshwater (kg/m^3) - seaiceFreshIceSpecificHeat, & ! specific heat of fresh ice (J/kg/K) - seaiceWaterVaporSpecificHeat, & ! specific heat of water vapor (J/kg/K) - seaiceAirSpecificHeat, & ! specific heat of air (J/kg/K) - seaiceSeaWaterSpecificHeat, & ! specific heat of ocn (J/kg/K) - seaiceLatentHeatVaporization, & ! latent heat, vaporization freshwater (J/kg) - seaiceZvir, & ! rh2o/rair - 1.0 - seaiceLatentHeatSublimation, & ! latent heat, sublimation freshwater (J/kg) - seaiceLatentHeatMelting, & ! latent heat of melting of fresh ice (J/kg) - seaiceIceSurfaceMeltingTemperature, & ! melting temp. ice top surface (C) - seaiceSnowSurfaceMeltingTemperature, & ! melting temp. snow top surface (C) - seaiceStefanBoltzmann, & ! J m-2 K-4 s-1 - seaiceIceSnowEmissivity, & ! emissivity of snow and ice - seaiceSnowSurfaceScatteringLayer, & ! snow surface scattering layer thickness (m) - seaiceStabilityReferenceHeight, & ! stability reference height (m) - seaiceFreshWaterFreezingPoint, & ! freezing temp of fresh ice (K) - seaiceIceSurfaceRoughness, & ! ice surface roughness (m) - seaiceVonKarmanConstant, & ! Von Karman constant - seaiceOceanAlbedo, & ! Ocean albedo - seaiceReferenceSalinity, & ! ice reference salinity (ppt) - seaiceMaximumSalinity, & ! ice maximum salinity (ppt) - seaiceMeltingTemperatureDepression, & ! melting temperature depression factor (C/ppt) - seaiceFrazilSalinityReduction, & ! bulk salinity reduction of newly formed frazil (ppt) - seaiceFrazilIcePorosity, & ! initial liquid fraction of frazil - seaicePi, & ! pi - seaiceGravity, & ! gravitational acceleration (m/s^2) - seaiceSnowPatchiness, & ! snow patchiness parameter - seaiceIceStrengthConstantHiblerP, & ! P* constant in Hibler strength formulation - seaiceIceStrengthConstantHiblerC, & ! C* constant in Hibler strength formulation - skeletalLayerThickness, & ! skeletal layer thickness - seaiceSnowMinimumDensity, & ! minimum snow density (kg/m^3) - seaiceBrineDynamicViscosity, & ! dynamic viscosity of brine (kg/m/s) - seaiceFreezingTemperatureConstant, &! constant freezing temp of seawater (C) - seaiceExtinctionCoef, & ! vis extnctn coef in ice, wvlngth<700nm (1/m) - seaiceFreshIceConductivity, & ! thermal conductivity of fresh ice(W/m/deg) - seaiceSnowMinimumThickness, & ! min snow thickness for computing zTsn (m) - seaiceFrazilMinimumThickness, & ! min thickness of new frazil ice - seaiceAlbedoWtVisibleDirect, & ! visible, direct - seaiceAlbedoWtNearIRDirect, & ! near IR, direct - seaiceAlbedoWtVisibleDiffuse, & ! visible, diffuse - seaiceAlbedoWtNearIRDiffuse, & ! near IR, diffuse - seaiceQsatQiceConstant, & ! constant for saturation humidity over ice - seaiceQsatTiceConstant, & ! constant for saturation humidity over ice - seaiceQsatQocnConstant, & ! constant for saturation humidity over ocean - seaiceQsatTocnConstant ! constant for saturation humidity over ocean - - type(domain_type), intent(inout) :: & - domain - - type(MPAS_pool_type), pointer :: & - snow - - character(len=strKIND), pointer :: & - config_thermodynamics_type, & - config_heat_conductivity_type, & - config_shortwave_type, & - config_albedo_type, & - config_ice_strength_formulation, & - config_ridging_participation_function, & - config_ridging_redistribution_function, & - config_atmos_boundary_method, & - config_itd_conversion_type, & - config_category_bounds_type, & - config_pond_refreezing_type, & - config_salt_flux_coupling_type, & - config_ocean_heat_transfer_type, & - config_frazil_coupling_type, & - config_sea_freezing_temperature_type, & - config_skeletal_bgc_flux_type, & - config_snow_redistribution_scheme - - logical, pointer :: & - config_use_snicar_ad, & - config_calc_surface_temperature, & - config_update_ocean_fluxes, & - config_use_form_drag, & - config_use_high_frequency_coupling, & - config_use_ocean_mixed_layer, & - config_calc_surface_stresses, & - config_use_vertical_tracers, & - config_scale_initial_vertical_bgc, & - config_use_vertical_biochemistry, & - config_use_shortwave_bioabsorption, & - config_use_skeletal_biochemistry, & - config_use_modal_aerosols, & - config_use_macromolecules, & - config_do_restart_bgc, & - config_use_snow_liquid_ponds, & - config_use_snow_grain_radius, & - config_use_shortwave_redistribution - - real(kind=RKIND), pointer :: & - config_min_friction_velocity, & - config_ice_ocean_drag_coefficient, & - config_snow_thermal_conductivity, & - config_rapid_mode_channel_radius, & - config_rapid_model_critical_Ra, & - config_rapid_mode_aspect_ratio, & - config_slow_mode_drainage_strength, & - config_slow_mode_critical_porosity, & - config_macro_drainage_timescale, & - config_congelation_ice_porosity, & -! config_frazil_ice_porosity, & -! config_frazil_salinity_reduction, & - config_visible_ice_albedo, & - config_infrared_ice_albedo, & - config_visible_snow_albedo, & - config_infrared_snow_albedo, & - config_variable_albedo_thickness_limit, & -! config_snow_surface_scattering_layer_depth, & - config_ice_shortwave_tuning_parameter, & - config_pond_shortwave_tuning_parameter, & - config_snow_shortwave_tuning_parameter, & - config_shortwave_redistribution_fraction, & - config_shortwave_redistribution_threshold, & - config_temp_change_snow_grain_radius_change, & - config_max_melting_snow_grain_radius, & - config_algae_absorption_coefficient, & - config_ridging_efolding_scale, & - config_ratio_ridging_work_to_PE, & - config_snow_to_ice_transition_depth, & - config_pond_flushing_factor, & - config_min_meltwater_retained_fraction, & - config_max_meltwater_retained_fraction, & - config_pond_depth_to_fraction_ratio, & - config_snow_on_pond_ice_tapering_parameter, & - config_critical_pond_ice_thickness, & - config_biogrid_bottom_molecular_sublayer, & - config_bio_gravity_drainage_length_scale, & - config_biogrid_top_molecular_sublayer, & - config_new_ice_fraction_biotracer, & - config_fraction_biotracer_in_frazil, & - config_snow_porosity_at_ice_surface, & - config_ratio_Si_to_N_diatoms, & - config_ratio_Si_to_N_small_plankton, & - config_ratio_Si_to_N_phaeocystis, & - config_ratio_S_to_N_diatoms, & - config_ratio_S_to_N_small_plankton, & - config_ratio_S_to_N_phaeocystis, & - config_ratio_Fe_to_C_diatoms, & - config_ratio_Fe_to_C_small_plankton, & - config_ratio_Fe_to_C_phaeocystis, & - config_ratio_Fe_to_N_diatoms, & - config_ratio_Fe_to_N_small_plankton, & - config_ratio_Fe_to_N_phaeocystis, & - config_ratio_Fe_to_DON, & - config_ratio_Fe_to_DOC_saccharids, & - config_ratio_Fe_to_DOC_lipids, & - config_respiration_fraction_of_growth, & - config_rapid_mobile_to_stationary_time, & - config_long_mobile_to_stationary_time, & - config_algal_maximum_velocity, & - config_ratio_Fe_to_dust, & - config_solubility_of_Fe_in_dust, & - config_chla_absorptivity_of_diatoms, & - config_chla_absorptivity_of_small_plankton, & - config_chla_absorptivity_of_phaeocystis, & - config_light_attenuation_diatoms, & - config_light_attenuation_small_plankton, & - config_light_attenuation_phaeocystis, & - config_light_inhibition_diatoms, & - config_light_inhibition_small_plankton, & - config_light_inhibition_phaeocystis, & - config_maximum_growth_rate_diatoms, & - config_maximum_growth_rate_small_plankton, & - config_maximum_growth_rate_phaeocystis, & - config_temperature_growth_diatoms, & - config_temperature_growth_small_plankton, & - config_temperature_growth_phaeocystis, & - config_grazed_fraction_diatoms, & - config_grazed_fraction_small_plankton, & - config_grazed_fraction_phaeocystis, & - config_mortality_diatoms, & - config_mortality_small_plankton, & - config_mortality_phaeocystis, & - config_temperature_mortality_diatoms, & - config_temperature_mortality_small_plankton, & - config_temperature_mortality_phaeocystis, & - config_exudation_diatoms, & - config_exudation_small_plankton, & - config_exudation_phaeocystis, & - config_nitrate_saturation_diatoms, & - config_nitrate_saturation_small_plankton, & - config_nitrate_saturation_phaeocystis, & - config_ammonium_saturation_diatoms, & - config_ammonium_saturation_small_plankton, & - config_ammonium_saturation_phaeocystis, & - config_silicate_saturation_diatoms, & - config_silicate_saturation_small_plankton, & - config_silicate_saturation_phaeocystis, & - config_iron_saturation_diatoms, & - config_iron_saturation_small_plankton, & - config_iron_saturation_phaeocystis, & - config_fraction_spilled_to_DON, & - config_degredation_of_DON, & - config_fraction_DON_ammonium, & - config_fraction_loss_to_saccharids, & - config_fraction_loss_to_lipids, & - config_fraction_exudation_to_saccharids, & - config_fraction_exudation_to_lipids, & - config_remineralization_saccharids, & - config_remineralization_lipids, & - config_maximum_brine_temperature, & - config_salinity_dependence_of_growth, & - config_minimum_optical_depth, & - config_slopped_grazing_fraction, & - config_excreted_fraction, & - config_fraction_mortality_to_ammonium, & - config_fraction_iron_remineralized, & - config_nitrification_rate, & - config_desorption_loss_particulate_iron, & - config_maximum_loss_fraction, & - config_maximum_ratio_iron_to_saccharids, & - config_respiration_loss_to_DMSPd, & - config_DMSP_to_DMS_conversion_fraction, & - config_DMSP_to_DMS_conversion_time, & - config_DMS_oxidation_time, & - config_mobility_type_diatoms, & - config_mobility_type_small_plankton, & - config_mobility_type_phaeocystis, & - config_mobility_type_nitrate, & - config_mobility_type_ammonium, & - config_mobility_type_silicate, & - config_mobility_type_DMSPp, & - config_mobility_type_DMSPd, & - config_mobility_type_humics, & - config_mobility_type_saccharids, & - config_mobility_type_lipids, & - config_mobility_type_inorganic_carbon, & - config_mobility_type_proteins, & - config_mobility_type_dissolved_iron, & - config_mobility_type_particulate_iron, & - config_mobility_type_black_carbon1, & - config_mobility_type_black_carbon2, & - config_mobility_type_dust1, & - config_mobility_type_dust2, & - config_mobility_type_dust3, & - config_mobility_type_dust4, & - config_ratio_C_to_N_diatoms, & - config_ratio_C_to_N_small_plankton, & - config_ratio_C_to_N_phaeocystis, & - config_ratio_chla_to_N_diatoms, & - config_ratio_chla_to_N_small_plankton, & - config_ratio_chla_to_N_phaeocystis, & - config_scales_absorption_diatoms, & - config_scales_absorption_small_plankton, & - config_scales_absorption_phaeocystis, & - config_ratio_C_to_N_proteins, & - config_fallen_snow_radius, & - config_new_snow_density, & - config_max_snow_density, & - config_minimum_wind_compaction, & - config_wind_compaction_factor, & - config_snow_redistribution_factor, & - config_max_dry_snow_radius - - real(kind=RKIND), dimension(:,:,:), pointer :: & - snowEmpiricalGrowthParameterTau, & - snowEmpiricalGrowthParameterKappa, & - snowPropertyRate - - integer, pointer :: & - config_boundary_layer_iteration_number, & - nGrainAgingTemperature, & - nGrainAgingTempGradient, & - nGrainAgingSnowDensity - - integer :: & - config_thermodynamics_type_int, & - config_ice_strength_formulation_int, & - config_ridging_participation_function_int, & - config_ridging_redistribution_function_int, & - config_itd_conversion_type_int, & - config_category_bounds_type_int - - character(len=strKIND) :: tmp_config_shortwave_type - character(len=strKIND) :: tmp_config_snw_ssp_table - character(len=strKIND) :: snw_aging_table = 'snicar' - - ! debugging - integer :: itmp1, itmp2 - real(kind=RKIND) :: rtmp1, rtmp2 - character(len=strKIND) :: ctmp1, ctmp2 - - call MPAS_pool_get_config(domain % configs, "config_thermodynamics_type", config_thermodynamics_type) - call MPAS_pool_get_config(domain % configs, "config_heat_conductivity_type", config_heat_conductivity_type) - call MPAS_pool_get_config(domain % configs, "config_ocean_heat_transfer_type", config_ocean_heat_transfer_type) - call MPAS_pool_get_config(domain % configs, "config_calc_surface_temperature", config_calc_surface_temperature) - call MPAS_pool_get_config(domain % configs, "config_update_ocean_fluxes", config_update_ocean_fluxes) - call MPAS_pool_get_config(domain % configs, "config_frazil_coupling_type", config_frazil_coupling_type) - call MPAS_pool_get_config(domain % configs, "config_min_friction_velocity", config_min_friction_velocity) - call MPAS_pool_get_config(domain % configs, "config_ice_ocean_drag_coefficient", config_ice_ocean_drag_coefficient) - call MPAS_pool_get_config(domain % configs, "config_snow_thermal_conductivity", config_snow_thermal_conductivity) - call MPAS_pool_get_config(domain % configs, "config_rapid_mode_channel_radius", config_rapid_mode_channel_radius) - call MPAS_pool_get_config(domain % configs, "config_rapid_model_critical_Ra", config_rapid_model_critical_Ra) - call MPAS_pool_get_config(domain % configs, "config_rapid_mode_aspect_ratio", config_rapid_mode_aspect_ratio) - call MPAS_pool_get_config(domain % configs, "config_slow_mode_drainage_strength", config_slow_mode_drainage_strength) - call MPAS_pool_get_config(domain % configs, "config_slow_mode_critical_porosity", config_slow_mode_critical_porosity) - call MPAS_pool_get_config(domain % configs, "config_macro_drainage_timescale", config_macro_drainage_timescale) - call MPAS_pool_get_config(domain % configs, "config_congelation_ice_porosity", config_congelation_ice_porosity) -! call MPAS_pool_get_config(domain % configs, "config_frazil_ice_porosity", config_frazil_ice_porosity) -! call MPAS_pool_get_config(domain % configs, "config_frazil_salinity_reduction", config_frazil_salinity_reduction) - call MPAS_pool_get_config(domain % configs, "config_shortwave_type", config_shortwave_type) - call MPAS_pool_get_config(domain % configs, "config_use_snicar_ad", config_use_snicar_ad) - call MPAS_pool_get_config(domain % configs, "config_albedo_type", config_albedo_type) - call MPAS_pool_get_config(domain % configs, "config_visible_ice_albedo", config_visible_ice_albedo) - call MPAS_pool_get_config(domain % configs, "config_infrared_ice_albedo", config_infrared_ice_albedo) - call MPAS_pool_get_config(domain % configs, "config_visible_snow_albedo", config_visible_snow_albedo) - call MPAS_pool_get_config(domain % configs, "config_infrared_snow_albedo", config_infrared_snow_albedo) - call MPAS_pool_get_config(domain % configs, "config_variable_albedo_thickness_limit", config_variable_albedo_thickness_limit) -! call MPAS_pool_get_config(domain % configs, "config_snow_surface_scattering_layer_depth", config_snow_surface_scattering_layer_depth) - call MPAS_pool_get_config(domain % configs, "config_ice_shortwave_tuning_parameter", config_ice_shortwave_tuning_parameter) - call MPAS_pool_get_config(domain % configs, "config_pond_shortwave_tuning_parameter", config_pond_shortwave_tuning_parameter) - call MPAS_pool_get_config(domain % configs, "config_snow_shortwave_tuning_parameter", config_snow_shortwave_tuning_parameter) - call MPAS_pool_get_config(domain % configs, "config_use_shortwave_redistribution", config_use_shortwave_redistribution) - call MPAS_pool_get_config(domain % configs, "config_shortwave_redistribution_fraction", config_shortwave_redistribution_fraction) - call MPAS_pool_get_config(domain % configs, "config_shortwave_redistribution_threshold", config_shortwave_redistribution_threshold) - call MPAS_pool_get_config(domain % configs, "config_temp_change_snow_grain_radius_change", & - config_temp_change_snow_grain_radius_change) - call MPAS_pool_get_config(domain % configs, "config_max_melting_snow_grain_radius", config_max_melting_snow_grain_radius) - call MPAS_pool_get_config(domain % configs, "config_algae_absorption_coefficient", config_algae_absorption_coefficient) - call MPAS_pool_get_config(domain % configs, "config_ice_strength_formulation", config_ice_strength_formulation) - call MPAS_pool_get_config(domain % configs, "config_ridging_participation_function", config_ridging_participation_function) - call MPAS_pool_get_config(domain % configs, "config_ridging_redistribution_function", config_ridging_redistribution_function) - call MPAS_pool_get_config(domain % configs, "config_ridging_efolding_scale", config_ridging_efolding_scale) - call MPAS_pool_get_config(domain % configs, "config_ratio_ridging_work_to_PE", config_ratio_ridging_work_to_PE) - call MPAS_pool_get_config(domain % configs, "config_atmos_boundary_method", config_atmos_boundary_method) - call MPAS_pool_get_config(domain % configs, "config_calc_surface_stresses", config_calc_surface_stresses) - call MPAS_pool_get_config(domain % configs, "config_use_form_drag", config_use_form_drag) - call MPAS_pool_get_config(domain % configs, "config_use_high_frequency_coupling", config_use_high_frequency_coupling) - call MPAS_pool_get_config(domain % configs, "config_boundary_layer_iteration_number", config_boundary_layer_iteration_number) - call MPAS_pool_get_config(domain % configs, "config_use_ocean_mixed_layer", config_use_ocean_mixed_layer) - call MPAS_pool_get_config(domain % configs, "config_sea_freezing_temperature_type", config_sea_freezing_temperature_type) - call MPAS_pool_get_config(domain % configs, "config_itd_conversion_type", config_itd_conversion_type) - call MPAS_pool_get_config(domain % configs, "config_category_bounds_type", config_category_bounds_type) - call MPAS_pool_get_config(domain % configs, "config_snow_to_ice_transition_depth", config_snow_to_ice_transition_depth) - call MPAS_pool_get_config(domain % configs, "config_pond_refreezing_type", config_pond_refreezing_type) - call MPAS_pool_get_config(domain % configs, "config_salt_flux_coupling_type", config_salt_flux_coupling_type) - call MPAS_pool_get_config(domain % configs, "config_pond_flushing_factor", config_pond_flushing_factor) - call MPAS_pool_get_config(domain % configs, "config_min_meltwater_retained_fraction", config_min_meltwater_retained_fraction) - call MPAS_pool_get_config(domain % configs, "config_max_meltwater_retained_fraction", config_max_meltwater_retained_fraction) - call MPAS_pool_get_config(domain % configs, "config_pond_depth_to_fraction_ratio", config_pond_depth_to_fraction_ratio) - call MPAS_pool_get_config(domain % configs, "config_snow_on_pond_ice_tapering_parameter", & - config_snow_on_pond_ice_tapering_parameter) - call MPAS_pool_get_config(domain % configs, "config_critical_pond_ice_thickness", config_critical_pond_ice_thickness) - call MPAS_pool_get_config(domain % configs, "config_skeletal_bgc_flux_type", config_skeletal_bgc_flux_type) - call MPAS_pool_get_config(domain % configs, "config_use_vertical_tracers", config_use_vertical_tracers) - call MPAS_pool_get_config(domain % configs, "config_scale_initial_vertical_bgc", config_scale_initial_vertical_bgc) - call MPAS_pool_get_config(domain % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) - call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) - call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols", config_use_modal_aerosols) - call MPAS_pool_get_config(domain % configs, "config_use_macromolecules", config_use_macromolecules) - call MPAS_pool_get_config(domain % configs, "config_do_restart_bgc", config_do_restart_bgc) - call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) - call MPAS_pool_get_config(domain % configs, "config_biogrid_bottom_molecular_sublayer", & - config_biogrid_bottom_molecular_sublayer) - call MPAS_pool_get_config(domain % configs, "config_bio_gravity_drainage_length_scale", & - config_bio_gravity_drainage_length_scale) - call MPAS_pool_get_config(domain % configs, "config_biogrid_top_molecular_sublayer", config_biogrid_top_molecular_sublayer) - call MPAS_pool_get_config(domain % configs, "config_new_ice_fraction_biotracer", config_new_ice_fraction_biotracer) - call MPAS_pool_get_config(domain % configs, "config_fraction_biotracer_in_frazil", config_fraction_biotracer_in_frazil) - call MPAS_pool_get_config(domain % configs, "config_snow_porosity_at_ice_surface", config_snow_porosity_at_ice_surface) - call MPAS_pool_get_config(domain % configs, "config_ratio_Si_to_N_diatoms", config_ratio_Si_to_N_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_Si_to_N_small_plankton", config_ratio_Si_to_N_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_Si_to_N_phaeocystis", config_ratio_Si_to_N_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_S_to_N_diatoms", config_ratio_S_to_N_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_S_to_N_small_plankton", config_ratio_S_to_N_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_S_to_N_phaeocystis", config_ratio_S_to_N_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_C_diatoms", config_ratio_Fe_to_C_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_C_small_plankton", config_ratio_Fe_to_C_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_C_phaeocystis", config_ratio_Fe_to_C_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_N_diatoms", config_ratio_Fe_to_N_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_N_small_plankton", config_ratio_Fe_to_N_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_N_phaeocystis", config_ratio_Fe_to_N_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_DON", config_ratio_Fe_to_DON) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_DOC_saccharids", config_ratio_Fe_to_DOC_saccharids) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_DOC_lipids", config_ratio_Fe_to_DOC_lipids) - call MPAS_pool_get_config(domain % configs, "config_respiration_fraction_of_growth", config_respiration_fraction_of_growth) - call MPAS_pool_get_config(domain % configs, "config_rapid_mobile_to_stationary_time", config_rapid_mobile_to_stationary_time) - call MPAS_pool_get_config(domain % configs, "config_long_mobile_to_stationary_time", config_long_mobile_to_stationary_time) - call MPAS_pool_get_config(domain % configs, "config_algal_maximum_velocity", config_algal_maximum_velocity) - call MPAS_pool_get_config(domain % configs, "config_ratio_Fe_to_dust", config_ratio_Fe_to_dust) - call MPAS_pool_get_config(domain % configs, "config_solubility_of_Fe_in_dust", config_solubility_of_Fe_in_dust) - call MPAS_pool_get_config(domain % configs, "config_chla_absorptivity_of_diatoms", config_chla_absorptivity_of_diatoms) - call MPAS_pool_get_config(domain % configs, "config_chla_absorptivity_of_small_plankton", & - config_chla_absorptivity_of_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_chla_absorptivity_of_phaeocystis", config_chla_absorptivity_of_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_light_attenuation_diatoms", config_light_attenuation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_light_attenuation_small_plankton", config_light_attenuation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_light_attenuation_phaeocystis", config_light_attenuation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_light_inhibition_diatoms", config_light_inhibition_diatoms) - call MPAS_pool_get_config(domain % configs, "config_light_inhibition_small_plankton", config_light_inhibition_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_light_inhibition_phaeocystis", config_light_inhibition_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_maximum_growth_rate_diatoms", config_maximum_growth_rate_diatoms) - call MPAS_pool_get_config(domain % configs, "config_maximum_growth_rate_small_plankton", & - config_maximum_growth_rate_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_maximum_growth_rate_phaeocystis", config_maximum_growth_rate_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_temperature_growth_diatoms", config_temperature_growth_diatoms) - call MPAS_pool_get_config(domain % configs, "config_temperature_growth_small_plankton", & - config_temperature_growth_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_temperature_growth_phaeocystis", config_temperature_growth_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_grazed_fraction_diatoms", config_grazed_fraction_diatoms) - call MPAS_pool_get_config(domain % configs, "config_grazed_fraction_small_plankton", config_grazed_fraction_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_grazed_fraction_phaeocystis", config_grazed_fraction_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_mortality_diatoms", config_mortality_diatoms) - call MPAS_pool_get_config(domain % configs, "config_mortality_small_plankton", config_mortality_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_mortality_phaeocystis", config_mortality_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_temperature_mortality_diatoms", config_temperature_mortality_diatoms) - call MPAS_pool_get_config(domain % configs, "config_temperature_mortality_small_plankton", & - config_temperature_mortality_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_temperature_mortality_phaeocystis", & - config_temperature_mortality_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_exudation_diatoms", config_exudation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_exudation_small_plankton", config_exudation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_exudation_phaeocystis", config_exudation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_nitrate_saturation_diatoms", config_nitrate_saturation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_nitrate_saturation_small_plankton", & - config_nitrate_saturation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_nitrate_saturation_phaeocystis", config_nitrate_saturation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ammonium_saturation_diatoms", config_ammonium_saturation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ammonium_saturation_small_plankton", & - config_ammonium_saturation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ammonium_saturation_phaeocystis", & - config_ammonium_saturation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_silicate_saturation_diatoms", config_silicate_saturation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_silicate_saturation_small_plankton", & - config_silicate_saturation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_silicate_saturation_phaeocystis", config_silicate_saturation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_iron_saturation_diatoms", config_iron_saturation_diatoms) - call MPAS_pool_get_config(domain % configs, "config_iron_saturation_small_plankton", config_iron_saturation_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_iron_saturation_phaeocystis", config_iron_saturation_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_fraction_spilled_to_DON", config_fraction_spilled_to_DON) - call MPAS_pool_get_config(domain % configs, "config_degredation_of_DON", config_degredation_of_DON) - call MPAS_pool_get_config(domain % configs, "config_fraction_DON_ammonium", config_fraction_DON_ammonium) - call MPAS_pool_get_config(domain % configs, "config_fraction_loss_to_saccharids", config_fraction_loss_to_saccharids) - call MPAS_pool_get_config(domain % configs, "config_fraction_loss_to_lipids", config_fraction_loss_to_lipids) - call MPAS_pool_get_config(domain % configs, "config_fraction_exudation_to_saccharids", config_fraction_exudation_to_saccharids) - call MPAS_pool_get_config(domain % configs, "config_fraction_exudation_to_lipids", config_fraction_exudation_to_lipids) - call MPAS_pool_get_config(domain % configs, "config_remineralization_saccharids", config_remineralization_saccharids) - call MPAS_pool_get_config(domain % configs, "config_remineralization_lipids", config_remineralization_lipids) - call MPAS_pool_get_config(domain % configs, "config_maximum_brine_temperature", config_maximum_brine_temperature) - call MPAS_pool_get_config(domain % configs, "config_salinity_dependence_of_growth", config_salinity_dependence_of_growth) - call MPAS_pool_get_config(domain % configs, "config_minimum_optical_depth", config_minimum_optical_depth) - call MPAS_pool_get_config(domain % configs, "config_slopped_grazing_fraction", config_slopped_grazing_fraction) - call MPAS_pool_get_config(domain % configs, "config_excreted_fraction", config_excreted_fraction) - call MPAS_pool_get_config(domain % configs, "config_fraction_mortality_to_ammonium", config_fraction_mortality_to_ammonium) - call MPAS_pool_get_config(domain % configs, "config_fraction_iron_remineralized", config_fraction_iron_remineralized) - call MPAS_pool_get_config(domain % configs, "config_nitrification_rate", config_nitrification_rate) - call MPAS_pool_get_config(domain % configs, "config_desorption_loss_particulate_iron", config_desorption_loss_particulate_iron) - call MPAS_pool_get_config(domain % configs, "config_maximum_loss_fraction", config_maximum_loss_fraction) - call MPAS_pool_get_config(domain % configs, "config_maximum_ratio_iron_to_saccharids", config_maximum_ratio_iron_to_saccharids) - call MPAS_pool_get_config(domain % configs, "config_respiration_loss_to_DMSPd", config_respiration_loss_to_DMSPd) - call MPAS_pool_get_config(domain % configs, "config_DMSP_to_DMS_conversion_fraction", config_DMSP_to_DMS_conversion_fraction) - call MPAS_pool_get_config(domain % configs, "config_DMSP_to_DMS_conversion_time", config_DMSP_to_DMS_conversion_time) - call MPAS_pool_get_config(domain % configs, "config_DMS_oxidation_time", config_DMS_oxidation_time) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_diatoms", config_mobility_type_diatoms) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_small_plankton", config_mobility_type_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_phaeocystis", config_mobility_type_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_nitrate", config_mobility_type_nitrate) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_ammonium", config_mobility_type_ammonium) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_silicate", config_mobility_type_silicate) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_DMSPp", config_mobility_type_DMSPp) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_DMSPd", config_mobility_type_DMSPd) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_humics", config_mobility_type_humics) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_saccharids", config_mobility_type_saccharids) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_lipids", config_mobility_type_lipids) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_inorganic_carbon", config_mobility_type_inorganic_carbon) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_proteins", config_mobility_type_proteins) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_dissolved_iron", config_mobility_type_dissolved_iron) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_particulate_iron", config_mobility_type_particulate_iron) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_black_carbon1", config_mobility_type_black_carbon1) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_black_carbon2", config_mobility_type_black_carbon2) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust1", config_mobility_type_dust1) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust2", config_mobility_type_dust2) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust3", config_mobility_type_dust3) - call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust4", config_mobility_type_dust4) - call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_diatoms", config_ratio_C_to_N_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_small_plankton", config_ratio_C_to_N_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_phaeocystis", config_ratio_C_to_N_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_chla_to_N_diatoms", config_ratio_chla_to_N_diatoms) - call MPAS_pool_get_config(domain % configs, "config_ratio_chla_to_N_small_plankton", config_ratio_chla_to_N_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_ratio_chla_to_N_phaeocystis", config_ratio_chla_to_N_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_scales_absorption_diatoms", config_scales_absorption_diatoms) - call MPAS_pool_get_config(domain % configs, "config_scales_absorption_small_plankton", config_scales_absorption_small_plankton) - call MPAS_pool_get_config(domain % configs, "config_scales_absorption_phaeocystis", config_scales_absorption_phaeocystis) - call MPAS_pool_get_config(domain % configs, "config_ratio_C_to_N_proteins", config_ratio_C_to_N_proteins) - call MPAS_pool_get_config(domain % configs, "config_snow_redistribution_scheme", config_snow_redistribution_scheme) - call MPAS_pool_get_config(domain % configs, "config_fallen_snow_radius", config_fallen_snow_radius) - call MPAS_pool_get_config(domain % configs, "config_use_snow_liquid_ponds", config_use_snow_liquid_ponds) - call MPAS_pool_get_config(domain % configs, "config_new_snow_density", config_new_snow_density) - call MPAS_pool_get_config(domain % configs, "config_max_snow_density", config_max_snow_density) - call MPAS_pool_get_config(domain % configs, "config_minimum_wind_compaction", config_minimum_wind_compaction) - call MPAS_pool_get_config(domain % configs, "config_wind_compaction_factor", config_wind_compaction_factor) - call MPAS_pool_get_config(domain % configs, "config_snow_redistribution_factor", config_snow_redistribution_factor) - call MPAS_pool_get_config(domain % configs, "config_max_dry_snow_radius", config_max_dry_snow_radius) - call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius) - call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingTemperature", nGrainAgingTemperature) - call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingTempGradient", nGrainAgingTempGradient) - call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingSnowDensity", nGrainAgingSnowDensity) - call MPAS_pool_get_subpool(domain % blocklist % structs, "snow", snow) - call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterTau", snowEmpiricalGrowthParameterTau) - call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterKappa", snowEmpiricalGrowthParameterKappa) - call MPAS_pool_get_array(snow, "snowPropertyRate", snowPropertyRate) + call MPAS_pool_get_config(domain % configs, "config_use_snow_grain_radius", config_use_snow_grain_radius) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingTemperature", nGrainAgingTemperature) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingTempGradient", nGrainAgingTempGradient) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nGrainAgingSnowDensity", nGrainAgingSnowDensity) + call MPAS_pool_get_subpool(domain % blocklist % structs, "snow", snow) + call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterTau", snowEmpiricalGrowthParameterTau) + call MPAS_pool_get_array(snow, "snowEmpiricalGrowthParameterKappa", snowEmpiricalGrowthParameterKappa) + call MPAS_pool_get_array(snow, "snowPropertyRate", snowPropertyRate) config_thermodynamics_type_int = config_cice_int("config_thermodynamics_type", config_thermodynamics_type) config_ice_strength_formulation_int = config_cice_int("config_ice_strength_formulation", config_ice_strength_formulation) @@ -12157,6 +10752,7 @@ subroutine init_icepack_package_configs(domain) snowpatch_in = seaiceSnowPatchiness, & ! ccsm3 radiation scheme !rhosi_in = , & ! brine, zbgc, zsalinity sk_l_in = skeletalLayerThickness, & ! + R_gC2molC_in = gramsCarbonPerMolCarbon, & saltmax_in = seaiceMaximumSalinity, & phi_init_in = seaiceFrazilIcePorosity, & !min_salin_in = , & ! ktherm=1, brine, zsalinity @@ -12391,9 +10987,9 @@ subroutine init_icepack_package_configs(domain) ! - make Lfresh optional for E3SM? ! tcraig, this will write out icepack parameters to fort.101, need to uncomment 3 lines -! if (mpas_log_info % taskID == 0) then -! call icepack_write_parameters(101) -! endif + if (mpas_log_info % taskID == 0) then + call icepack_write_parameters(101) + endif ! call seaice_icepack_write_warnings(icepack_warnings_aborted()) call mpas_log_write(" ----- compare values after icepack init -----") @@ -15726,15 +14322,6 @@ subroutine seaice_icepack_reinitialize_diagnostics_bgc(domain) end if -! if (config_use_vertical_zsalinity) then !echmod deprecate -! call MPAS_pool_get_array(biogeochemistryPool, "zSalinityFlux", zSalinityFlux) -! call MPAS_pool_get_array(biogeochemistryPool, "zSalinityGDFlux", zSalinityGDFlux) - -! zSalinityFlux = 0.0_RKIND -! zSalinityGDFlux = 0.0_RKIND - -! end if - call MPAS_pool_get_array(biogeochemistryPool, "netBrineHeight", netBrineHeight) call MPAS_pool_get_array(biogeochemistryPool, "oceanBioFluxes", oceanBioFluxes) call MPAS_pool_get_array(biogeochemistryPool, "atmosIceBioFluxes", atmosIceBioFluxes) @@ -16745,7 +15332,7 @@ end subroutine seaice_ocean_carbon_flux ! !----------------------------------------------------------------------- - subroutine seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxes,iCell) + subroutine seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxes) real(kind=RKIND), intent(out) :: & oceanCarbonFlux @@ -16753,9 +15340,6 @@ subroutine seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux,oceanBioFluxes,iC real(kind=RKIND), dimension(:), intent(in) :: & oceanBioFluxes - integer, intent(in) :: & - iCell - type(block_type), intent(in) :: & block From 105526017a97d110f36f8ad9a7783ca520beb183 Mon Sep 17 00:00:00 2001 From: hollyhan Date: Mon, 18 Mar 2024 10:55:50 -0700 Subject: [PATCH 070/388] Update the SeaLevelModel submodule --- components/mpas-albany-landice/src/SeaLevelModel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/SeaLevelModel b/components/mpas-albany-landice/src/SeaLevelModel index 26c156da219..5bb102d6750 160000 --- a/components/mpas-albany-landice/src/SeaLevelModel +++ b/components/mpas-albany-landice/src/SeaLevelModel @@ -1 +1 @@ -Subproject commit 26c156da2191df360e1040e0141534178674fc82 +Subproject commit 5bb102d6750b1437f6a5305cdd244cbd3776c32b From 95e7295b02636685be997f6d78eed2117890038b Mon Sep 17 00:00:00 2001 From: Matthew Hoffman Date: Tue, 19 Mar 2024 12:18:54 -0600 Subject: [PATCH 071/388] Revisions from code review --- .../mpas-albany-landice/src/mode_forward/mpas_li_thermal.F | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F index 65c30096352..acc5048e3a4 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_thermal.F @@ -70,7 +70,7 @@ module li_thermal ! Note: kelvin_to_celsius = 273.15 (perhaps it should be called celsius_to_kelvin?) real (kind=RKIND), parameter :: & - maxtempThreshold = 0.1_RKIND + kelvin_to_celsius, & + maxtempThreshold = 1e-6_RKIND + kelvin_to_celsius, & mintempThreshold = -100._RKIND + kelvin_to_celsius !*********************************************************************** @@ -2847,7 +2847,7 @@ subroutine basal_melt_grounded_ice(& ! Update basal water thickness based on melting or freezing (same for enthalpy or temperature) if (groundedBasalMassBal(iCell) > 0.0) then - ! for freezing conditions (+SMB), limit positive BMB to the available basal water + ! for freezing conditions, limit positive BMB to the available basal water groundedBasalMassBal(iCell) = min(groundedBasalMassBal(iCell), basalWaterThickness(iCell) / deltat) endif basalWaterThickness(iCell) = basalWaterThickness(iCell) - deltat*groundedBasalMassBal(iCell) From 0af5931b90c565976fdcf94472ab187903ae6d50 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 26 Mar 2024 12:38:59 -0700 Subject: [PATCH 072/388] PAM VT update --- .../eam/src/physics/crm/pam/pam_driver.cpp | 14 ++++++------- .../physics/crm/pam/pam_variance_transport.h | 20 +++++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index 2453f2ad61b..e6f85ed0d5a 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -25,7 +25,7 @@ #include "p3_f90.hpp" #include "pam_debug.h" -bool constexpr enable_check_state = true; +bool constexpr enable_check_state = false; extern "C" void pam_driver() { //------------------------------------------------------------------------------------------------ @@ -180,10 +180,11 @@ extern "C" void pam_driver() { // Apply forcing tendencies if (use_MMF_VT) { pam_variance_transport_apply_forcing(coupler); } - coupler.run_module( "apply_gcm_forcing_tendencies" , modules::apply_gcm_forcing_tendencies ); if (enable_check_state) { pam_debug_check_state(coupler, 2, nstep); } - coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); + coupler.run_module( "apply_gcm_forcing_tendencies" , modules::apply_gcm_forcing_tendencies ); if (enable_check_state) { pam_debug_check_state(coupler, 3, nstep); } + coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); + if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } // Dynamics if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } @@ -191,13 +192,12 @@ extern "C" void pam_driver() { coupler.run_module( "dycore", [&] (pam::PamCoupler &coupler) {dycore.timeStep(coupler);} ); if (do_density_save_recall) { pam_state_recall_dry_density(coupler); } if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"dycor"); } - if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } + if (enable_check_state) { pam_debug_check_state(coupler, 5, nstep); } // Sponge layer damping if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } coupler.run_module( "sponge_layer", modules::sponge_layer ); if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sponge"); } - // if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } // Apply hyperdiffusion to account for lack of horizontal mixing in SHOC pam_hyperdiffusion(coupler); @@ -207,13 +207,13 @@ extern "C" void pam_driver() { if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } coupler.run_module( "sgs", [&] (pam::PamCoupler &coupler) {sgs .timeStep(coupler);} ); if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sgs"); } - if (enable_check_state) { pam_debug_check_state(coupler, 5, nstep); } + if (enable_check_state) { pam_debug_check_state(coupler, 6, nstep); } // Microphysics - P3 if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } coupler.run_module( "micro", [&] (pam::PamCoupler &coupler) {micro .timeStep(coupler);} ); if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"micro"); } - if (enable_check_state) { pam_debug_check_state(coupler, 6, nstep); } + if (enable_check_state) { pam_debug_check_state(coupler, 7, nstep); } // CRM mean state acceleration if (use_crm_accel && !coupler.get_option("crm_acceleration_ceaseflag")) { diff --git a/components/eam/src/physics/crm/pam/pam_variance_transport.h b/components/eam/src/physics/crm/pam/pam_variance_transport.h index b7067631203..1033df4280d 100644 --- a/components/eam/src/physics/crm/pam/pam_variance_transport.h +++ b/components/eam/src/physics/crm/pam/pam_variance_transport.h @@ -2,6 +2,7 @@ #include "pam_coupler.h" + inline void pam_variance_transport_init( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; @@ -24,6 +25,7 @@ inline void pam_variance_transport_init( pam::PamCoupler &coupler ) { //------------------------------------------------------------------------------------------------ } + inline void pam_variance_transport_diagnose( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; @@ -83,6 +85,7 @@ inline void pam_variance_transport_diagnose( pam::PamCoupler &coupler ) { //------------------------------------------------------------------------------------------------ } + inline void pam_variance_transport_compute_forcing( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; @@ -135,9 +138,10 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { // large-scale forcing from variance transport. This is meant to // protect against creating unstable situations, although // problematic scenarios were extremely rare in testing. - // A scaling limit of +/- 10% was found to be adequate. - real constexpr pert_scale_min = 1.0 - 0.005; - real constexpr pert_scale_max = 1.0 + 0.005; + // A scaling limit of +/- 10% was found to be adequate in SAM, + // but PAM seems much more sensitive (not sure why), so we use 0.1% here + real constexpr pert_scale_min = 1.0 - 0.001; + real constexpr pert_scale_max = 1.0 + 0.001; //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); auto rhov = dm_device.get("water_vapor" ); @@ -162,14 +166,15 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { //------------------------------------------------------------------------------------------------ // calculate scaling factor for local perturbations parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { + real tmp; // initialize scaling factors to 1.0 temp_pert_scale(k,n) = 1.0; rhov_pert_scale(k,n) = 1.0; uvel_pert_scale(k,n) = 1.0; - // set scaling factors as long as there are perturbations to scale - if (vt_temp(k,n)>0.0) { temp_pert_scale(k,n) = sqrt( 1.0 + crm_dt * vt_temp_forcing_tend(k,n) / vt_temp(k,n) ); } - if (vt_rhov(k,n)>0.0) { rhov_pert_scale(k,n) = sqrt( 1.0 + crm_dt * vt_rhov_forcing_tend(k,n) / vt_rhov(k,n) ); } - if (vt_uvel(k,n)>0.0) { uvel_pert_scale(k,n) = sqrt( 1.0 + crm_dt * vt_uvel_forcing_tend(k,n) / vt_uvel(k,n) ); } + // calculate variance scaling factor + tmp = 1.+crm_dt*vt_temp_forcing_tend(k,n)/vt_temp(k,n); if (tmp>0){ temp_pert_scale(k,n) = sqrt(tmp); } + tmp = 1.+crm_dt*vt_rhov_forcing_tend(k,n)/vt_rhov(k,n); if (tmp>0){ rhov_pert_scale(k,n) = sqrt(tmp); } + tmp = 1.+crm_dt*vt_uvel_forcing_tend(k,n)/vt_uvel(k,n); if (tmp>0){ uvel_pert_scale(k,n) = sqrt(tmp); } // enforce minimum scaling temp_pert_scale(k,n) = std::max( temp_pert_scale(k,n), pert_scale_min ); rhov_pert_scale(k,n) = std::max( rhov_pert_scale(k,n), pert_scale_min ); @@ -261,7 +266,6 @@ inline void pam_variance_transport_copy_to_host( pam::PamCoupler &coupler ) { vt_temp_feedback_tend.deep_copy_to(output_vt_temp_tend_host); vt_rhov_feedback_tend.deep_copy_to(output_vt_rhov_tend_host); vt_uvel_feedback_tend.deep_copy_to(output_vt_uvel_tend_host); - yakl::fence(); //------------------------------------------------------------------------------------------------ } From 6fe86f61e08038fb95f964b0cfb5907d5a53423a Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 26 Mar 2024 12:47:40 -0700 Subject: [PATCH 073/388] update PAM submodule --- components/eam/src/physics/crm/pam/external | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/external b/components/eam/src/physics/crm/pam/external index 9d692dccdd6..ff652f3f2a6 160000 --- a/components/eam/src/physics/crm/pam/external +++ b/components/eam/src/physics/crm/pam/external @@ -1 +1 @@ -Subproject commit 9d692dccdd67d9c4dc278c76290504a2af8cd187 +Subproject commit ff652f3f2a6c2d675cd957883245aa6c036ef110 From 59b9476bbc96ed060ff12e4a7ba3480795b67872 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 26 Mar 2024 12:48:49 -0700 Subject: [PATCH 074/388] update PAM hyperdiffusion timescale default --- components/eam/src/physics/crm/pam/pam_hyperdiffusion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h index 4452c583afe..b632b0e4909 100644 --- a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h +++ b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h @@ -28,7 +28,7 @@ inline void pam_hyperdiffusion( pam::PamCoupler &coupler ) { #ifdef MMF_PAM_HDT real constexpr hd_timescale = MMF_PAM_HDT; // damping time scale [sec] #else - real constexpr hd_timescale = 10.0; // damping time scale [sec] + real constexpr hd_timescale = 60.0; // damping time scale [sec] #endif //------------------------------------------------------------------------------------------------ real4d hd_temp("hd_temp",nz,ny,nx,nens); From 1bc8307c0bd724847bc866b3c86d07d3f51c4dda Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 27 Mar 2024 11:40:59 -0700 Subject: [PATCH 075/388] Always remove small islands Always remove small islands, even if calving is turned off. Previously, remove_small_islands was only called from within each calving routine, which caused issues with AIS simulations with only restore_calving_front. --- .../src/mode_forward/mpas_li_calving.F | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 304ed0b0349..a86612ad00e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -315,7 +315,8 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) ! now also remove any icebergs call remove_icebergs(domain) - ! Final operations after calving has been applied. + ! Final operations after calving has been applied, including removal + ! of small islands block => domain % blocklist do while (associated(block)) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) @@ -324,6 +325,7 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + call remove_small_islands(meshPool, geometryPool) ! In data calving mode we just calculate what should be calved but don't actually calve it. ! So set thickness back to original value. if (config_data_calving) then @@ -927,8 +929,6 @@ subroutine thickness_calving(domain, calvingFraction, err) ! === apply calving === thickness(:) = thickness(:) - calvingThickness(:) - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -1003,8 +1003,6 @@ subroutine floating_calving(domain, calvingFraction, err) ! === apply calving === thickness(:) = thickness(:) - calvingThickness(:) - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -1180,8 +1178,6 @@ subroutine topographic_calving(domain, calvingFraction, err) ! === apply calving === thickness(:) = thickness(:) - calvingThickness(:) - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -1412,8 +1408,6 @@ subroutine eigencalving(domain, err) enddo ! TODO: global reduce & reporting on amount of calving generated in this step - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -1596,8 +1590,6 @@ subroutine specified_calving_velocity(domain, err) enddo ! TODO: global reduce & reporting on amount of calving generated in this step - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -1985,8 +1977,6 @@ subroutine von_Mises_calving(domain, err) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) err = ior(err, err_tmp) - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo ! associated(block) @@ -2256,7 +2246,6 @@ subroutine ismip6_retreat(domain, err) ! update mask call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) err = ior(err, err_tmp) - call remove_small_islands(meshPool, geometryPool) deallocate(submergedArea) @@ -3326,8 +3315,6 @@ subroutine damage_calving(domain, err) enddo ! TODO: global reduce & reporting on amount of calving generated in this step - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo @@ -3986,8 +3973,6 @@ subroutine mask_calving(domain, err) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) err = ior(err, err_tmp) - call remove_small_islands(meshPool, geometryPool) - block => block % next enddo From dc672a666686f36032e244e33e16c5b8ae16858b Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Thu, 28 Mar 2024 16:54:47 -0500 Subject: [PATCH 076/388] Avoids division by small number in update vertical bio tracers -Cleans up some missing bgc info in Registry (more to do) -Adds some additional info to carbon conservation analysis member -Saves bgc ocean fluxes weighted by ice area (for carbon conservation) -Comments out $omp statements around step therm1 (code was crashing -with seg fault) -Removes and cleans up unnecessary write statements for carbon debugging Tested with E3SM-Project/Icepack.git branch njeffery/merge-fixes-to-bgc commit c090b4b20e4ec0317d2c7d742c5ab291ec7a2240 BFB except correcting a seg fault --- components/mpas-seaice/src/Registry.xml | 163 ++++++++- .../Registry_seaice_conservation_check.xml | 6 + .../mpas_seaice_conservation_check.F | 77 ++--- .../mpas-seaice/src/column/ice_algae.F90 | 33 +- .../mpas-seaice/src/column/ice_colpkg.F90 | 2 +- .../mpas-seaice/src/column/ice_therm_itd.F90 | 2 +- .../mpas-seaice/src/column/ice_zbgc.F90 | 8 +- .../src/shared/mpas_seaice_column.F | 60 +++- .../src/shared/mpas_seaice_icepack.F | 314 +++++------------- 9 files changed, 376 insertions(+), 289 deletions(-) diff --git a/components/mpas-seaice/src/Registry.xml b/components/mpas-seaice/src/Registry.xml index ed39007ef72..6eb70ead768 100644 --- a/components/mpas-seaice/src/Registry.xml +++ b/components/mpas-seaice/src/Registry.xml @@ -5312,7 +5312,9 @@ type="real" dimensions="nCells Time" units="mmol m-2 s-1" - description="Total ocean carbon flux (positive into the ocean)" + description="Total ocean carbon flux (positive + into the ocean) weighted bysea ice + area fraction" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> + + + + + + + + + + + + + + + + puny) then ! loop over new grid cells do k2 = 1, nbiolyr @@ -840,7 +842,9 @@ subroutine update_vertical_bio_tracers(nbiolyr, trc, h1, h2, trc0, zspace) trc2(k2) = trc2(k2)/zspace(k2)/h2 !(rnilyr * trc2(k2)) / h2 enddo ! k2 - + else + trc2 = trc + endif ! h2 > 0 ! update vertical tracer array with the adjusted tracer trc = trc2 diff --git a/components/mpas-seaice/src/shared/mpas_seaice_column.F b/components/mpas-seaice/src/shared/mpas_seaice_column.F index 1b736c4b0cc..80a00a154d9 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_column.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_column.F @@ -4922,7 +4922,17 @@ subroutine seaice_column_coupling_prep(domain) oceanDMSPdFlux, & oceanHumicsFlux, & oceanDustIronFlux, & - totalOceanCarbonFlux + oceanBlackCarbonFlux, & + totalOceanCarbonFlux, & + oceanNitrateFluxArea, & + oceanSilicateFluxArea, & + oceanAmmoniumFluxArea, & + oceanDMSFluxArea, & + oceanDMSPpFluxArea, & + oceanDMSPdFluxArea, & + oceanHumicsFluxArea, & + oceanDustIronFluxArea, & + oceanBlackCarbonFluxArea real(kind=RKIND), dimension(:,:), pointer :: & albedoVisibleDirectCategory, & @@ -4939,7 +4949,13 @@ subroutine seaice_column_coupling_prep(domain) oceanDICFlux, & oceanDONFlux, & oceanParticulateIronFlux, & - oceanDissolvedIronFlux + oceanDissolvedIronFlux, & + oceanAlgaeFluxArea, & + oceanDOCFluxArea, & + oceanDICFluxArea, & + oceanDONFluxArea, & + oceanParticulateIronFluxArea, & + oceanDissolvedIronFluxArea real(kind=RKIND), dimension(:,:,:), pointer :: & iceAreaCategory @@ -5062,6 +5078,7 @@ subroutine seaice_column_coupling_prep(domain) call MPAS_pool_get_array(biogeochemistry, "oceanDMSPdFlux", oceanDMSPdFlux) call MPAS_pool_get_array(biogeochemistry, "oceanHumicsFlux", oceanHumicsFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDustIronFlux", oceanDustIronFlux) + call MPAS_pool_get_array(biogeochemistry, "oceanBlackCarbonFlux", oceanBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxes", oceanBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanAlgaeFlux", oceanAlgaeFlux) call MPAS_pool_get_array(biogeochemistry, "oceanDOCFlux", oceanDOCFlux) @@ -5071,6 +5088,22 @@ subroutine seaice_column_coupling_prep(domain) call MPAS_pool_get_array(biogeochemistry, "oceanDissolvedIronFlux", oceanDissolvedIronFlux) call MPAS_pool_get_array(biogeochemistry, "totalOceanCarbonFlux", totalOceanCarbonFlux) + call MPAS_pool_get_array(biogeochemistry, "oceanNitrateFluxArea", oceanNitrateFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanSilicateFluxArea", oceanSilicateFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanAmmoniumFluxArea", oceanAmmoniumFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSFluxArea", oceanDMSFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSPpFluxArea", oceanDMSPpFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSPdFluxArea", oceanDMSPdFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanHumicsFluxArea", oceanHumicsFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDustIronFluxArea", oceanDustIronFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanBlackCarbonFluxArea", oceanBlackCarbonFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanAlgaeFluxArea", oceanAlgaeFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDOCFluxArea", oceanDOCFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDICFluxArea", oceanDICFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDONFluxArea", oceanDONFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanParticulateIronFluxArea", oceanParticulateIronFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDissolvedIronFluxArea", oceanDissolvedIronFluxArea) + call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers) call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType) call MPAS_pool_get_dimension(mesh, "maxDOCType", maxDOCType) @@ -5194,6 +5227,7 @@ subroutine seaice_column_coupling_prep(domain) oceanDMSPdFlux(iCell) = 0.0_RKIND oceanDMSFlux(iCell) = 0.0_RKIND oceanDustIronFlux(iCell) = 0.0_RKIND + oceanBlackCarbonFlux(iCell) = 0.0_RKIND oceanHumicsFlux(iCell) = 0.0_RKIND do iBioTracers = 1, ciceTracerObject % nBioTracers @@ -5206,6 +5240,7 @@ subroutine seaice_column_coupling_prep(domain) do iBioTracers = 1, maxAlgaeType iBioData = iBioData+1 oceanAlgaeFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanAlgaeFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanAlgaeFlux(iBioTracers,iCell) * ratio_C_to_N(iBioTracers) enddo @@ -5213,11 +5248,13 @@ subroutine seaice_column_coupling_prep(domain) ! Nitrate iBioData = iBioData+1 oceanNitrateFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanNitrateFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! Polysaccharids and Lipids do iBioTracers = 1, maxDOCType iBioData = iBioData+1 oceanDOCFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDOCFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDOCFlux(iBioTracers,iCell) enddo @@ -5226,6 +5263,7 @@ subroutine seaice_column_coupling_prep(domain) do iBioTracers = 1, maxDICType iBioData = iBioData+1 oceanDICFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDICFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDICFlux(iBioTracers,iCell) enddo @@ -5236,22 +5274,27 @@ subroutine seaice_column_coupling_prep(domain) ! Ammonium iBioData = iBioData+1 oceanAmmoniumFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanAmmoniumFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! Silicate iBioData = iBioData+1 oceanSilicateFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanSilicateFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMSPp iBioData = iBioData+1 oceanDMSPpFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSPpFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMSPd iBioData = iBioData+1 oceanDMSPdFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSPdFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMS iBioData = iBioData+1 oceanDMSFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! PON iBioData = iBioData+1 @@ -5260,6 +5303,7 @@ subroutine seaice_column_coupling_prep(domain) do iBioTracers = 1, maxDONType iBioData = iBioData+1 oceanDONFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDONFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDONFlux(iBioTracers,iCell) * config_ratio_C_to_N_proteins enddo @@ -5268,26 +5312,34 @@ subroutine seaice_column_coupling_prep(domain) do iBioTracers = 1, maxIronType iBioData = iBioData+1 oceanDissolvedIronFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDissolvedIronFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) enddo ! Particulate Iron do iBioTracers = 1, maxIronType iBioData = iBioData+1 oceanParticulateIronFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanParticulateIronFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) enddo - ! Black Carbon (not saved) - iBioData = iBioData + maxBCType + ! Black Carbon (combined; saved for conservation) + do iBioTracers = 1, maxBCType + iBioData = iBioData + 1 + oceanBlackCarbonFlux(iCell) = oceanBlackCarbonFlux(iCell) + oceanBioFluxesAll(iBioData) + enddo + oceanBlackCarbonFluxArea(iCell) = oceanBlackCarbonFlux(iCell) ! Dust (combined) do iBioTracers = 1, maxDustType iBioData = iBioData+1 oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) + oceanBioFluxesAll(iBioData) enddo + oceanDustIronFluxArea(iCell) = oceanDustIronFlux(iCell) ! Humics iBioData = iBioData+1 oceanHumicsFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanHumicsFluxArea(iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanHumicsFlux(iCell) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 05e6f98f337..8255e731586 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -1256,7 +1256,8 @@ end subroutine seaice_icepack_postdynamics_time_integration subroutine column_vertical_thermodynamics(domain, clock) use icepack_intfc, only: & - icepack_step_therm1 + icepack_step_therm1, & + icepack_warnings_clear use seaice_constants, only: & seaicePuny @@ -1690,14 +1691,18 @@ subroutine column_vertical_thermodynamics(domain, clock) endif ! code abort - abortFlag = .false. - abortMessage = "" + !abortFlag = .false. + !abortMessage = "" - !$omp parallel do default(shared) private(iCategory,iAerosol,northernHemisphereMask,& - !$omp& abortMessage) firstprivate(specificSnowAerosol,specificIceAerosol) & - !$omp& reduction(.or.:abortFlag) + !$offomp parallel do default(shared) private(iCategory,iAerosol,northernHemisphereMask,& + !$offomp& abortMessage) firstprivate(specificSnowAerosol,specificIceAerosol) + !$offomp& reduction(.or.:abortFlag) do iCell = 1, nCellsSolve + ! code abort + abortFlag = .false. + abortMessage = "" + ! initial state values iceAreaCellInitial(iCell) = iceAreaCell(iCell) @@ -1737,6 +1742,7 @@ subroutine column_vertical_thermodynamics(domain, clock) northernHemisphereMask = .false. endif + call icepack_warnings_clear() call icepack_step_therm1(& dt=config_dt, & ncat=nCategories, & @@ -1871,6 +1877,7 @@ subroutine column_vertical_thermodynamics(domain, clock) frz_onset=freezeOnset(iCell), & yday=dayOfYear, & prescribed_ice=config_use_prescribed_ice) + abortFlag = icepack_warnings_aborted() call seaice_icepack_write_warnings(abortFlag) @@ -2059,7 +2066,6 @@ subroutine column_vertical_thermodynamics(domain, clock) enddo ! iCategory endif - enddo ! iCell ! error-checking @@ -2203,27 +2209,16 @@ subroutine column_itd_thermodynamics(domain, clock) iBioData, & iBioLayers - ! test carbon conservation real(kind=RKIND), dimension(:,:), allocatable :: & - totalCarbonCatFinal, & - totalCarbonCatInitial, & oceanBioFluxesTemp - real(kind=RKIND), dimension(:), allocatable :: & - verticalGridSpace, & - totalCarbonFinal, & - totalCarbonInitial, & - oceanCarbonFlux, & - carbonError - logical, dimension(:), allocatable :: & newlyFormedIceLogical logical :: & abortFlag, & setGetPhysicsTracers, & - setGetBGCTracers, & - checkCarbon + setGetBGCTracers character(len=strKIND) :: & abortMessage, & @@ -2235,8 +2230,6 @@ subroutine column_itd_thermodynamics(domain, clock) ! day of year call get_day_of_year(clock, dayOfYear) - checkCarbon = .false. - block => domain % blocklist do while (associated(block)) @@ -2333,27 +2326,6 @@ subroutine column_itd_thermodynamics(domain, clock) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) - allocate(verticalGridSpace(nBioLayersP1)) - if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) - allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) - allocate(totalCarbonInitial(nCellsSolve)) - allocate(totalCarbonFinal(nCellsSolve)) - allocate(oceanCarbonFlux(nCellsSolve)) - allocate(carbonError(nCellsSolve)) - else - allocate(totalCarbonCatFinal(1,1)) - allocate(totalCarbonCatInitial(1,1)) - allocate(totalCarbonInitial(1)) - allocate(totalCarbonFinal(1)) - allocate(oceanCarbonFlux(1)) - allocate(carbonError(1)) - endif - - verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) - verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND - verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) - setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) @@ -2385,14 +2357,6 @@ subroutine column_itd_thermodynamics(domain, clock) call set_cice_tracer_array_category(block, ciceTracerObject,& tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) then - totalCarbonInitial(iCell) = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - do iCategory = 1,nCategories - totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) - enddo - endif - oceanBioFluxesTemp(:,iCell) = 0.0_RKIND ! CICE calculates the Sig Wave Height from the wave spectrum as follows before step therm2: @@ -2464,9 +2428,6 @@ subroutine column_itd_thermodynamics(domain, clock) oceanBioFluxes(iBioTracers,iCell) = oceanBioFluxes(iBioTracers,iCell) + oceanBioFluxesTemp(iBioTracers,iCell) enddo - abortFlag = icepack_warnings_aborted() - call seaice_icepack_write_warnings(abortFlag) - ! update do iCategory = 1, nCategories newlyFormedIce(iCategory,iCell) = 0 @@ -2477,41 +2438,13 @@ subroutine column_itd_thermodynamics(domain, clock) call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) then - totalCarbonFinal(iCell) = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell)) - do iCategory = 1,nCategories - totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) - enddo - carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) - - if (abs(carbonError(iCell)) > max(seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell)))) then - call mpas_log_write("column_step_therm2, carbon conservation error", messageType=MPAS_LOG_ERR) - call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) - call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) - call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) - call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) - call mpas_log_write("config_dt: $r", messageType=MPAS_LOG_ERR, realArgs=(/config_dt/)) - - do iCategory = 1, nCategories - call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) - call mpas_log_write("iceAreaCategoryInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory,iCell)/)) - call mpas_log_write("iceVolumeCategoryInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategoryInitial(iCategory,iCell)/)) - call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) - call mpas_log_write("iceVolumeCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategory(1,iCategory,iCell)/)) - enddo - endif - endif - + abortFlag = icepack_warnings_aborted() ! cell-specific abort message if (abortFlag) then call mpas_log_write("column_itd_thermodynamics: "//trim(abortMessage) , messageType=MPAS_LOG_ERR) call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) endif + call seaice_icepack_write_warnings(abortFlag) enddo ! iCell @@ -2519,17 +2452,9 @@ subroutine column_itd_thermodynamics(domain, clock) call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - deallocate(totalCarbonInitial) - deallocate(totalCarbonFinal) - deallocate(oceanCarbonFlux) - deallocate(carbonError) - ! newly formed ice deallocate(newlyFormedIceLogical) deallocate(oceanBioFluxesTemp) - deallocate(verticalGridSpace) block => block % next end do @@ -3041,11 +2966,6 @@ subroutine column_radiation(domain, clock, lInitialization) iAerosol, & iBioTracers - integer, dimension(:), allocatable :: & - index_shortwaveAerosol, & - index_verticalAerosolsConc, & - index_algaeConc - real(kind=RKIND) :: & dayOfYear, & lonCellColumn @@ -3163,28 +3083,6 @@ subroutine column_radiation(domain, clock, lInitialization) ! aerosols array allocate(aerosolsArray(4*nAerosols,nCategories)) - allocate(index_shortwaveAerosol(maxAerosolType)) - allocate(index_verticalAerosolsConc(maxAerosolType)) - allocate(index_algaeConc(nAlgae)) - - if (.not. config_use_zaerosols) then - index_shortwaveAerosol(1:maxAerosolType) = 1 - index_verticalAerosolsConc(1:maxAerosolType) = 1 - else - do iAerosol = 1, maxAerosolType - index_shortwaveAerosol(iAerosol) = ciceTracerObject % index_verticalAerosolsConcShortwave(iAerosol) - index_verticalAerosolsConc(iAerosol) = ciceTracerObject % index_verticalAerosolsConc(iAerosol) - enddo - endif - - if (.not. config_use_column_biogeochemistry) then - index_algaeConc(1:nAlgae) = 1 - else - do iBioTracers = 1, nAlgae - index_algaeConc(iBioTracers) = ciceTracerObject % index_algaeConc(iBioTracers) - enddo - endif - setGetPhysicsTracers = .true. setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) @@ -3192,7 +3090,7 @@ subroutine column_radiation(domain, clock, lInitialization) allocate(snow_grain_radius(nSnowLayers,nCategories)) !$omp parallel do default(shared) & - !$omp& firstprivate(aerosolsArray,index_shortwaveAerosol,snow_grain_radius) & + !$omp& firstprivate(aerosolsArray,snow_grain_radius) & !$omp& private(iCategory,iAerosol,lonCellColumn,iSnowLayer) do iCell = 1, nCellsSolve @@ -3282,9 +3180,6 @@ subroutine column_radiation(domain, clock, lInitialization) ! aerosols array deallocate(aerosolsArray) - deallocate(index_shortwaveAerosol) - deallocate(index_verticalAerosolsConc) - deallocate(index_algaeConc) block => block % next end do @@ -3404,29 +3299,15 @@ subroutine column_ridging(domain) iBioData, & iBioLayers - ! test carbon conservation real(kind=RKIND), dimension(:,:), allocatable :: & - totalCarbonCatFinal, & - totalCarbonCatInitial, & oceanBioFluxesTemp - real(kind=RKIND), dimension(:), allocatable :: & - verticalGridSpace, & - totalCarbonFinal, & - totalCarbonInitial, & - oceanCarbonFlux, & - carbonError, & - iceAreaCategoryInitial - logical, dimension(:), allocatable :: & newlyFormedIceLogical logical :: & setGetPhysicsTracers, & - setGetBGCTracers, & - checkCarbon - - checkCarbon = .false. + setGetBGCTracers block => domain % blocklist do while (associated(block)) @@ -3507,28 +3388,6 @@ subroutine column_ridging(domain) setGetBGCTracers = (config_use_column_biogeochemistry .or. config_use_zaerosols) allocate(oceanBioFluxesTemp(ciceTracerObject % nBioTracers,nCellsSolve)) - allocate(verticalGridSpace(nBioLayersP1)) - if (checkCarbon) then - allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) - allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) - allocate(totalCarbonInitial(nCellsSolve)) - allocate(totalCarbonFinal(nCellsSolve)) - allocate(oceanCarbonFlux(nCellsSolve)) - allocate(carbonError(nCellsSolve)) - allocate(iceAreaCategoryInitial(nCategories)) - else - allocate(totalCarbonCatFinal(1,1)) - allocate(totalCarbonCatInitial(1,1)) - allocate(totalCarbonInitial(1)) - allocate(totalCarbonFinal(1)) - allocate(oceanCarbonFlux(1)) - allocate(carbonError(1)) - allocate(iceAreaCategoryInitial(1)) - endif - - verticalGridSpace(:) = 1.0_RKIND/real(nBioLayers,kind=RKIND) - verticalGridSpace(1) = verticalGridSpace(1)/2.0_RKIND - verticalGridSpace(nBioLayersP1) = verticalGridSpace(1) do iCell = 1, nCellsSolve @@ -3541,15 +3400,6 @@ subroutine column_ridging(domain) call set_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) then - totalCarbonInitial(iCell) = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatInitial(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - do iCategory = 1,nCategories - iceAreaCategoryInitial(iCategory) = iceAreaCategory(1,iCategory,iCell) - totalCarbonInitial(iCell) = totalCarbonInitial(iCell) + totalCarbonCatInitial(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) - enddo - endif - oceanBioFluxesTemp(:,iCell) = 0.0_RKIND call icepack_step_ridge(& @@ -3609,53 +3459,12 @@ subroutine column_ridging(domain) call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) - if (checkCarbon) then - totalCarbonFinal(iCell) = 0.0_RKIND - call seaice_total_carbon_content_category(block,totalCarbonCatFinal(:,iCell),iceAreaCategory(1,:,:),iceVolumeCategory(1,:,:),iCell) - call seaice_ocean_carbon_flux_cell(block,oceanCarbonFlux(iCell),oceanBioFluxesTemp(:,iCell)) - do iCategory = 1,nCategories - totalCarbonFinal(iCell) = totalCarbonFinal(iCell) + totalCarbonCatFinal(iCategory,iCell)*iceAreaCategory(1,iCategory,iCell) - enddo - carbonError(iCell) = (totalCarbonFinal(iCell) - totalCarbonInitial(iCell))/config_dt + oceanCarbonFlux(iCell) - - if (abs(carbonError(iCell)) > max(10.0_RKIND*seaicePuny,1.0e-14_RKIND*abs(oceanCarbonFlux(iCell))) .and. & - MAXVAL(iceAreaCategory(1,:,iCell)) > seaicePuny .and. & - MAXVAL(iceAreaCategoryInitial(:)) > seaicePuny) then - call mpas_log_write("icepack_step_ridge, carbon conservation error", messageType=MPAS_LOG_ERR) - call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - call mpas_log_write("carbonError: $r", messageType=MPAS_LOG_ERR, realArgs=(/carbonError(iCell)/)) - call mpas_log_write("totalCarbonInitial: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonInitial(iCell)/)) - call mpas_log_write("totalCarbonFinal: $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonFinal(iCell)/)) - call mpas_log_write("oceanCarbonFlux: $r", messageType=MPAS_LOG_ERR, realArgs=(/oceanCarbonFlux(iCell)/)) - call mpas_log_write("config_dt: $r", messageType=MPAS_LOG_ERR, realArgs=(/config_dt/)) - - do iCategory = 1, nCategories - call mpas_log_write("iCategory: $i", messageType=MPAS_LOG_ERR, intArgs=(/iCategory/)) - call mpas_log_write("totalCarbonCatFinal(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatFinal(iCategory,iCell)/)) - call mpas_log_write("totalCarbonCatInitial(iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/totalCarbonCatInitial(iCategory,iCell)/)) - call mpas_log_write("iceAreaCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategory(1,iCategory,iCell)/)) - call mpas_log_write("iceAreaCategoryInitial(iCategory): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceAreaCategoryInitial(iCategory)/)) - call mpas_log_write("iceVolumeCategory(1,iCategory,iCell): $r", messageType=MPAS_LOG_ERR, realArgs=(/iceVolumeCategory(1,iCategory,iCell)/)) - enddo - endif - endif - + call seaice_icepack_write_warnings(icepack_warnings_aborted()) enddo ! iCell - call seaice_icepack_write_warnings(icepack_warnings_aborted()) -! check carbon - deallocate(oceanBioFluxesTemp) - deallocate(verticalGridSpace) - deallocate(totalCarbonCatFinal) - deallocate(totalCarbonCatInitial) - deallocate(totalCarbonInitial) - deallocate(totalCarbonFinal) - deallocate(oceanCarbonFlux) - deallocate(carbonError) - deallocate(iceAreaCategoryInitial) - ! newly formed ice deallocate(newlyFormedIceLogical) + deallocate(oceanBioFluxesTemp) block => block % next end do @@ -3984,9 +3793,9 @@ subroutine column_biogeochemistry(domain) ! newly formed ice allocate(newlyFormedIceLogical(nCategories)) allocate(brineHeightCatInitial(nCategories,nCellsSolve)) - allocate(carbonError(nCellsSolve)) if (checkCarbon) then + allocate(carbonError(nCellsSolve)) allocate(totalCarbonCatFinal(nCategories,nCellsSolve)) allocate(totalCarbonCatInitial(nCategories,nCellsSolve)) allocate(totalCarbonCatFlux(nCategories,nCellsSolve)) @@ -3995,6 +3804,7 @@ subroutine column_biogeochemistry(domain) allocate(totalCarbonInitial(nCellsSolve)) allocate(totalCarbonFlux(nCellsSolve)) else + allocate(carbonError(1)) allocate(totalCarbonCatFinal(1,1)) allocate(totalCarbonCatInitial(1,1)) allocate(totalCarbonCatFlux(1,1)) @@ -4153,7 +3963,6 @@ subroutine column_biogeochemistry(domain) bioTemperatureIceCell=bgridTemperatureIceCell(:,iCell)) abortFlag = icepack_warnings_aborted() - call seaice_icepack_write_warnings(abortFlag) call get_cice_tracer_array_category(block, ciceTracerObject, & tracerArrayCategory, iCell, setGetPhysicsTracers, setGetBGCTracers) @@ -4215,13 +4024,16 @@ subroutine column_biogeochemistry(domain) if (newlyFormedIceLogical(iCategory)) newlyFormedIce(iCategory,iCell) = 1 enddo ! iCategory + ! code abort + if (abortFlag) then + call mpas_log_write("column_biogeochemistry: "//trim(abortMessage) , messageType=MPAS_LOG_ERR) + call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) + endif + + call seaice_icepack_write_warnings(abortFlag) + enddo ! iCell - ! code abort - if (abortFlag) then - call mpas_log_write("column_biogeochemistry: "//trim(abortMessage) , messageType=MPAS_LOG_ERR) - call mpas_log_write("iCell: $i", messageType=MPAS_LOG_ERR, intArgs=(/indexToCellID(iCell)/)) - endif call seaice_critical_error_write_block(domain, block, abortFlag) call seaice_check_critical_error(domain, abortFlag) @@ -4232,10 +4044,10 @@ subroutine column_biogeochemistry(domain) deallocate(totalCarbonFinal) deallocate(totalCarbonInitial) deallocate(totalCarbonFlux) + deallocate(carbonError) deallocate(brineHeightCatInitial) deallocate(newlyFormedIceLogical) - deallocate(carbonError) block => block % next end do @@ -4531,6 +4343,9 @@ subroutine seaice_icepack_aggregate(domain) nCellsSolve, & nCategories + integer, dimension(:), pointer :: & + indexToCellID + logical :: & setGetPhysicsTracers, & setGetBGCTracers @@ -4549,6 +4364,7 @@ subroutine seaice_icepack_aggregate(domain) call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) call MPAS_pool_get_dimension(mesh, "nCategories", nCategories) + call MPAS_pool_get_array(mesh, "indexToCellID", indexToCellID) call MPAS_pool_get_array(tracers, "iceAreaCategory", iceAreaCategory, 1) call MPAS_pool_get_array(tracers, "iceVolumeCategory", iceVolumeCategory, 1) @@ -4765,7 +4581,16 @@ subroutine seaice_icepack_coupling_prep(domain) oceanHumicsFlux, & oceanDustIronFlux, & oceanBlackCarbonFlux, & - totalOceanCarbonFlux + totalOceanCarbonFlux, & + oceanNitrateFluxArea, & + oceanSilicateFluxArea, & + oceanAmmoniumFluxArea, & + oceanDMSFluxArea, & + oceanDMSPpFluxArea, & + oceanDMSPdFluxArea, & + oceanHumicsFluxArea, & + oceanDustIronFluxArea, & + oceanBlackCarbonFluxArea real(kind=RKIND), dimension(:,:), pointer :: & albedoVisibleDirectCategory, & @@ -4782,7 +4607,13 @@ subroutine seaice_icepack_coupling_prep(domain) oceanDICFlux, & oceanDONFlux, & oceanParticulateIronFlux, & - oceanDissolvedIronFlux + oceanDissolvedIronFlux, & + oceanAlgaeFluxArea, & + oceanDOCFluxArea, & + oceanDICFluxArea, & + oceanDONFluxArea, & + oceanParticulateIronFluxArea, & + oceanDissolvedIronFluxArea real(kind=RKIND), dimension(:,:,:), pointer :: & iceAreaCategory @@ -4915,6 +4746,22 @@ subroutine seaice_icepack_coupling_prep(domain) call MPAS_pool_get_array(biogeochemistry, "oceanDissolvedIronFlux", oceanDissolvedIronFlux) call MPAS_pool_get_array(biogeochemistry, "totalOceanCarbonFlux", totalOceanCarbonFlux) + call MPAS_pool_get_array(biogeochemistry, "oceanNitrateFluxArea", oceanNitrateFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanSilicateFluxArea", oceanSilicateFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanAmmoniumFluxArea", oceanAmmoniumFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSFluxArea", oceanDMSFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSPpFluxArea", oceanDMSPpFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDMSPdFluxArea", oceanDMSPdFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanHumicsFluxArea", oceanHumicsFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDustIronFluxArea", oceanDustIronFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanBlackCarbonFluxArea", oceanBlackCarbonFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanAlgaeFluxArea", oceanAlgaeFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDOCFluxArea", oceanDOCFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDICFluxArea", oceanDICFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDONFluxArea", oceanDONFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanParticulateIronFluxArea", oceanParticulateIronFluxArea) + call MPAS_pool_get_array(biogeochemistry, "oceanDissolvedIronFluxArea", oceanDissolvedIronFluxArea) + call MPAS_pool_get_dimension(mesh, "nZBGCTracers", nZBGCTracers) call MPAS_pool_get_dimension(mesh, "maxAlgaeType", maxAlgaeType) call MPAS_pool_get_dimension(mesh, "maxDOCType", maxDOCType) @@ -5051,6 +4898,7 @@ subroutine seaice_icepack_coupling_prep(domain) do iBioTracers = 1, maxAlgaeType iBioData = iBioData+1 oceanAlgaeFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanAlgaeFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanAlgaeFlux(iBioTracers,iCell) * ratio_C_to_N(iBioTracers) enddo @@ -5058,11 +4906,13 @@ subroutine seaice_icepack_coupling_prep(domain) ! Nitrate iBioData = iBioData+1 oceanNitrateFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanNitrateFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! Polysaccharids and Lipids do iBioTracers = 1, maxDOCType iBioData = iBioData+1 oceanDOCFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDOCFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDOCFlux(iBioTracers,iCell) enddo @@ -5071,6 +4921,7 @@ subroutine seaice_icepack_coupling_prep(domain) do iBioTracers = 1, maxDICType iBioData = iBioData+1 oceanDICFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDICFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDICFlux(iBioTracers,iCell) enddo @@ -5081,22 +4932,27 @@ subroutine seaice_icepack_coupling_prep(domain) ! Ammonium iBioData = iBioData+1 oceanAmmoniumFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanAmmoniumFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! Silicate iBioData = iBioData+1 oceanSilicateFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanSilicateFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMSPp iBioData = iBioData+1 oceanDMSPpFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSPpFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMSPd iBioData = iBioData+1 oceanDMSPdFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSPdFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! DMS iBioData = iBioData+1 oceanDMSFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanDMSFluxArea(iCell) = oceanBioFluxesAll(iBioData) ! PON iBioData = iBioData+1 @@ -5105,6 +4961,7 @@ subroutine seaice_icepack_coupling_prep(domain) do iBioTracers = 1, maxDONType iBioData = iBioData+1 oceanDONFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDONFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & oceanDONFlux(iBioTracers,iCell) * config_ratio_C_to_N_proteins enddo @@ -5113,31 +4970,36 @@ subroutine seaice_icepack_coupling_prep(domain) do iBioTracers = 1, maxIronType iBioData = iBioData+1 oceanDissolvedIronFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanDissolvedIronFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) enddo ! Particulate Iron do iBioTracers = 1, maxIronType iBioData = iBioData+1 oceanParticulateIronFlux(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) + oceanParticulateIronFluxArea(iBioTracers,iCell) = oceanBioFluxesAll(iBioData) enddo ! Black Carbon (combined; saved for conservation) do iBioTracers = 1, maxBCType iBioData = iBioData + 1 oceanBlackCarbonFlux(iCell) = oceanBlackCarbonFlux(iCell) + oceanBioFluxesAll(iBioData) - enddo + enddo + oceanBlackCarbonFluxArea(iCell) = oceanBlackCarbonFlux(iCell) ! Dust (combined) do iBioTracers = 1, maxDustType iBioData = iBioData+1 oceanDustIronFlux(iCell) = oceanDustIronFlux(iCell) + oceanBioFluxesAll(iBioData) - enddo + enddo + oceanDustIronFluxArea(iCell) = oceanDustIronFlux(iCell) ! Humics iBioData = iBioData+1 oceanHumicsFlux(iCell) = oceanBioFluxesAll(iBioData) + oceanHumicsFluxArea(iCell) = oceanBioFluxesAll(iBioData) totalOceanCarbonFlux(iCell) = totalOceanCarbonFlux(iCell) + & - oceanHumicsFlux(iCell) + oceanHumicsFlux(iCell) endif ! config_use_column_biogeochemistry .or. config_use_zaerosols @@ -15759,12 +15621,12 @@ subroutine seaice_icepack_write_warnings(logAsErrors) if (logAsErrors) then do iWarning = 1, size(warnings) call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_ERR) - enddo ! iWarning + enddo ! iWarning call mpas_log_write("icepack aborted", MPAS_LOG_CRIT) else do iWarning = 1, size(warnings) call mpas_log_write(trim(warnings(iWarning)), messageType=MPAS_LOG_WARN) - enddo ! iWarning + enddo ! iWarning endif call icepack_warnings_clear() From 2305a7dbfd1923929289274a7b9ceb5a582c89c5 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 29 Mar 2024 14:29:01 -0500 Subject: [PATCH 077/388] Changed Icepack submodule url Now consistent with E3SM master BFB --- .gitmodules | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 84c10e97a8c..69d56e14036 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,7 +76,6 @@ [submodule "components/mpas-seaice/src/icepack"] path = components/mpas-seaice/src/icepack url = git@github.com:E3SM-Project/Icepack.git - branch = njeffery/merge-fixes-to-bgc [submodule "externals/haero"] path = externals/haero url = git@github.com:eagles-project/haero.git From ebdb83028c0c026a227c038ffdf9279c575bab42 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 29 Mar 2024 14:05:15 -0700 Subject: [PATCH 078/388] revert CRM timestep to 5 sec for MMF2 --- components/eam/cime_config/config_component.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/cime_config/config_component.xml b/components/eam/cime_config/config_component.xml index 577c3256db4..784fe44195e 100755 --- a/components/eam/cime_config/config_component.xml +++ b/components/eam/cime_config/config_component.xml @@ -72,8 +72,8 @@ -crm samxx -crm_dt 10 - -crm pam -pam_dycor spam -crm_dt 8 - -crm pam -pam_dycor awfl -crm_dt 8 + -crm pam -pam_dycor spam -crm_dt 5 + -crm pam -pam_dycor awfl -crm_dt 5 -use_MMF -nlev 60 -crm_nz 50 -crm_dx 2000 -crm_nx 64 -crm_ny 1 -crm_nx_rad 4 -crm_ny_rad 1 -crm_dx 2000 -crm_nx 45 -crm_ny 1 -crm_nx_rad 5 -crm_ny_rad 1 From 63570638abe7c46aa3b74e81dfc0dfb06cdf83a3 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Sat, 30 Mar 2024 10:22:04 -0500 Subject: [PATCH 079/388] Corrects error in black carbon conservation member Small error introduced in last commit - broke compile BFB --- .../src/analysis_members/mpas_seaice_conservation_check.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-seaice/src/analysis_members/mpas_seaice_conservation_check.F b/components/mpas-seaice/src/analysis_members/mpas_seaice_conservation_check.F index ca7811a0967..0dac34ca240 100644 --- a/components/mpas-seaice/src/analysis_members/mpas_seaice_conservation_check.F +++ b/components/mpas-seaice/src/analysis_members/mpas_seaice_conservation_check.F @@ -2391,7 +2391,7 @@ subroutine black_carbon_conservation(domain, err) nZBGC = nZBGC+1 totalAtmBC2Cell = atmosBlackCarbonFlux(nZBGC,iCell) * areaCell(iCell)* & iceAreaCellInitial(iCell) - totalOceanBlackCarbonCell = oceanBlackCarbonFlux(iCell) * areaCell(iCell) + totalOceanBlackCarbonCell = oceanBlackCarbonFluxArea(iCell) * areaCell(iCell) totalAtmBlackCarbonCell = totalAtmBC1Cell + totalAtmBC2Cell do iHemisphere = 1, nHemispheres From c8339245c735ffd25cd40aae6578f062c09d8a9f Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 25 Mar 2024 09:57:30 -0700 Subject: [PATCH 080/388] Enforce waterFluxMask = 2 at domain boundaries Adds requirement that waterFluxMask must equal 2 (no-flow conditions) at domain boundaries. Edges on domain boundaries will automatically have a waterFluxMask set to 2 if not done in input file (warning message will be issued in log file if this occurs). --- .../mode_forward/mpas_li_subglacial_hydro.F | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index cffd631f00b..25192502b8e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2213,9 +2213,11 @@ subroutine calc_hydro_mask(domain) integer, dimension(:), pointer :: hydroTerrestrialMarginMask integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:), pointer :: cellMask - integer, pointer :: nEdgesSolve + integer, dimension(:), pointer :: waterFluxMask + integer, pointer :: nEdgesSolve, nCells integer :: cell1, cell2, iEdge real (kind=RKIND), pointer :: config_sea_level + integer :: wfmWarning call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) @@ -2228,14 +2230,29 @@ subroutine calc_hydro_mask(domain) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(hydroPool, 'hydroTerrestrialMarginMask', hydroTerrestrialMarginMask) + call mpas_pool_get_array(hydroPool, 'waterFluxMask', waterFluxMask) call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) - + call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + hydroMarineMarginMask(:) = 0 + hydroTerrestrialMarginMask(:) = 0 + wfmWarning = 0 + do iEdge = 1, nEdgesSolve cell1 = cellsOnEdge(1, iEdge) cell2 = cellsOnEdge(2, iEdge) - ! We are looking for edges with 1 edge grounded ice and the other edge floating ice or open ocean + + !ensure no-flow conditions on edges of domain if not set up + !in input file + if ( ((cell1 == nCells + 1) .or. (cell2 == nCells +1 )) & + .and. (waterFluxMask(iEdge) .ne. 2)) then + waterFluxMask(iEdge) = 2 + wfmWarning = 1 + endif + + ! hydroMarineMarginMask: We are looking for edges with 1 edge grounded ice and the other edge floating ice or open ocean + ! Exclude no-flow boundaries if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & (li_mask_is_floating_ice(cellMask(cell2)) .or. & ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then @@ -2245,13 +2262,9 @@ subroutine calc_hydro_mask(domain) ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then hydroMarineMarginMask(iEdge) = 1 endif - enddo - - hydroTerrestrialMarginMask(:) = 0 - do iEdge = 1, nEdgesSolve - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) - !Look for edges with 1 cell on grounding ice and the other cell on land without ice + + ! hydroTerrestrialMarginMask: Look for edges with 1 cell on grounding ice and the other cell on land without ice + ! Exclude no-flow boundaries if ((li_mask_is_grounded_ice(cellMask(cell1))) .and. ( .not. li_mask_is_ice(cellMask(cell2))) & .and. (bedTopography(cell2) >= config_sea_level)) then hydroTerrestrialMarginMask(iEdge) = 1 @@ -2264,8 +2277,13 @@ subroutine calc_hydro_mask(domain) block => block % next end do + if (wfmWarning == 1) then + call mpas_log_write('WARNING: Changing waterFluxMask to enforce no-flow conditions at domain boundaries') + endif call mpas_timer_start("halo updates") call mpas_dmpar_field_halo_exch(domain, 'hydroMarineMarginMask') + call mpas_dmpar_field_halo_exch(domain, 'hydroTerrestrialMarginMask') + call mpas_dmpar_field_halo_exch(domain, 'waterFluxMask') call mpas_timer_stop("halo updates") !-------------------------------------------------------------------- From 01a92b7f67beda8105c969b2940d3cc0e23dbbda Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 2 Apr 2024 09:15:31 -0600 Subject: [PATCH 081/388] Zero normal gradients at waterFluxMask = 2 Uses waterFluxMaskk=2 to zero out hydropotential and waterPressure normal slopes instead of using exterior domain boundary condition. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 25192502b8e..48ae15cf3fa 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -911,9 +911,7 @@ subroutine calc_edge_quantities(block, err) ! zero gradients at boundaries of the mesh do iEdge = 1, nEdges - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) - if ((cell1 == nCells+1) .or. (cell2 == nCells+1)) then + if (waterFluxMask(iEdge) == 2) then hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND hydropotentialSlopeNormal(iEdge) = 0.0_RKIND waterPressureSlopeNormal(iEdge) = 0.0_RKIND From a5856def8b5507fb1b54f6ad92ac8ac615aa21ed Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 2 Apr 2024 09:47:15 -0600 Subject: [PATCH 082/388] Zero tangent gradients at waterFluxMask = 2 Uses waterFlaskMask==2 as criteria for zeroing out hydropotential tangent slopes along domain boundaries. --- .../mode_forward/mpas_li_subglacial_hydro.F | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 48ae15cf3fa..ab4f427e2b1 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -786,8 +786,8 @@ subroutine calc_edge_quantities(block, err) integer, pointer :: nEdges integer, pointer :: nCells integer, pointer :: nVertices - integer :: iEdge, cell1, cell2 integer :: i, j, iVertex, iCell + integer :: iEdge, cell1, cell2 real (kind=RKIND) :: velSign integer :: numGroundedCells integer :: err_tmp @@ -946,7 +946,6 @@ subroutine calc_edge_quantities(block, err) ! contaminated values. call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) call mpas_pool_get_array(meshPool, 'verticesOnEdge', verticesOnEdge) - call mpas_pool_get_array(meshPool, 'cellsOnVertex', cellsOnVertex) select case (trim(config_SGH_tangent_slope_calculation)) case ('from_vertex_barycentric', 'from_vertex_barycentric_kiteareas') do iEdge = 1, nEdges @@ -960,17 +959,11 @@ subroutine calc_edge_quantities(block, err) hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND hydropotentialSlopeTangent(iEdge) = 0.0_RKIND endif - ! check for edges where a vertex is on the edge of the mesh and zero the tangent slope there - do i = 1, 2 - iVertex = verticesOnEdge(i, iEdge) - do j = 1, 3 - iCell = cellsOnVertex(j, iVertex) - if (iCell == nCells + 1) then - hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND - hydropotentialSlopeTangent(iEdge) = 0.0_RKIND - endif - enddo - enddo + ! zero tangent slope at waterFluxMask==2 + if (waterFluxMask(iEdge) == 2) then + hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND + hydropotentialSlopeTangent(iEdge) = 0.0_RKIND + endif end do ! edges case ('from_normal_slope') ! Do first with hydropotentialBase @@ -985,6 +978,11 @@ subroutine calc_edge_quantities(block, err) hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND hydropotentialSlopeTangent(iEdge) = 0.0_RKIND endif + if (waterFluxMask(iEdge) == 2) then + hydropotentialBaseSlopeTangent(iEdge) = 0.0_RKIND + hydropotentialSlopeTangent(iEdge) = 0.0_RKIND + endif + end do ! edges case default call mpas_log_write('Invalid value for config_SGH_tangent_slope_calculation.', MPAS_LOG_ERR) From 684bd0fce66633ab9bd24365d89b6711cf8759f7 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 2 Apr 2024 11:57:19 -0600 Subject: [PATCH 083/388] remove + 1e-30 to gradMagPhiBaseEdge in effectiveConducEdge Removes 1e-30 addition to gradMagPhiBaseEdge when calculating effectiveConducEdge. Allows gradMagPhiBaseEdge to actually be zero when hydropotential slopes are both zero, otherwise this line causes a blow up in effectiveConductEdge. This is now consistent with the way gradMagPhiEdge is used in the channel model --- .../mode_forward/mpas_li_subglacial_hydro.F | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index ab4f427e2b1..a83a35c5d2a 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1000,16 +1000,27 @@ subroutine calc_edge_quantities(block, err) if (conduc_coeff_drowned > 0.0_RKIND) then ! Use a thickness weighted conductivity coeff. when water thickness exceeds bump height do iEdge = 1, nEdges - conduc_coeff_wtd = (conduc_coeff * min(waterThicknessEdge(iEdge), bedRoughMax) + & - conduc_coeff_drowned * max(waterThicknessEdge(iEdge) - bedRoughMax, 0.0_RKIND)) / & - (waterThicknessEdge(iEdge) + 1.0e-16_RKIND) ! Regularization only applies where value doesn't matter - effectiveConducEdge(iEdge) = conduc_coeff_wtd * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) * & - (gradMagPhiBaseEdge(iEdge)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization + if (gradMagPhiBaseEdge(iEdge) < 0.01_RKIND) then + effectiveConducEdge(iEdge) = 0.0_RKIND + else + conduc_coeff_wtd = (conduc_coeff * min(waterThicknessEdge(iEdge), bedRoughMax) + & + conduc_coeff_drowned * max(waterThicknessEdge(iEdge) - bedRoughMax, 0.0_RKIND)) / & + (waterThicknessEdge(iEdge) + 1.0e-16_RKIND) ! Regularization only applies where value doesn't matter + + effectiveConducEdge(iEdge) = conduc_coeff_wtd * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) * & + gradMagPhiBaseEdge(iEdge)**(beta - 2.0_RKIND) + endif end do else - ! Just use a single conductivity coeff. - effectiveConducEdge(:) = conduc_coeff * waterThicknessEdge(:)**(alpha-1.0_RKIND) *& - (gradMagPhiBaseEdge(:)+1.0e-30_RKIND)**(beta - 2.0_RKIND) ! small value used for regularization + do iEdge = 1, nEdges + ! Just use a single conductivity coeff. + if (gradMagPhiBaseEdge(iEdge) < 0.01_RKIND) then + effectiveConducEdge(iEdge) = 0.0_RKIND + else + effectiveConducEdge(iEdge) = conduc_coeff * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) *& + gradMagPhiBaseEdge(iEdge)**(beta - 2.0_RKIND) + endif + enddo endif ! calculate diffusivity on edges From d43658b64f72c8956fae670945cac2244652fa14 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 19 Mar 2024 15:09:15 -0600 Subject: [PATCH 084/388] no margin masks where waterFluxMask=2 Adds logic to calculations of hydroMarineMarginMask and hydroTerrestrialMarginMask so that they are not defined where waterFluxMask = 2. Allows interior of ice sheet to have zero thickness if desired without being counted to either mask. Important for restricting parts of domain to only thawed ice (masking out frozen bed). --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index a83a35c5d2a..ec55b53fa0b 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2221,7 +2221,8 @@ subroutine calc_hydro_mask(domain) integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:), pointer :: cellMask integer, dimension(:), pointer :: waterFluxMask - integer, pointer :: nEdgesSolve, nCells + integer, pointer :: nEdgesSolve + integer, pointer :: nCells integer :: cell1, cell2, iEdge real (kind=RKIND), pointer :: config_sea_level integer :: wfmWarning @@ -2262,21 +2263,25 @@ subroutine calc_hydro_mask(domain) ! Exclude no-flow boundaries if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & (li_mask_is_floating_ice(cellMask(cell2)) .or. & - ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then + ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) & + .and. (waterFluxMask(iEdge) .ne. 2) ) then hydroMarineMarginMask(iEdge) = 1 elseif ( (li_mask_is_grounded_ice(cellMask(cell2))) .and. & (li_mask_is_floating_ice(cellMask(cell1)) .or. & - ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then + ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) & + .and. (waterFluxMask(iEdge) .ne. 2) ) then hydroMarineMarginMask(iEdge) = 1 endif ! hydroTerrestrialMarginMask: Look for edges with 1 cell on grounding ice and the other cell on land without ice ! Exclude no-flow boundaries if ((li_mask_is_grounded_ice(cellMask(cell1))) .and. ( .not. li_mask_is_ice(cellMask(cell2))) & - .and. (bedTopography(cell2) >= config_sea_level)) then + .and. (bedTopography(cell2) >= config_sea_level) & + .and. (waterFluxMask(iEdge) .ne. 2) ) then hydroTerrestrialMarginMask(iEdge) = 1 elseif ((li_mask_is_grounded_ice(cellMask(cell2))) .and. ( .not. li_mask_is_ice(cellMask(cell1))) & - .and. (bedTopography(cell1) >= config_sea_level)) then + .and. (bedTopography(cell1) >= config_sea_level) & + .and. (waterFluxMask(iEdge) .ne. 2) ) then hydroTerrestrialMarginMask(iEdge) = 1 endif enddo From d367aa6536afaa81e7f9e18fe601ab1d54fdec4d Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 3 Apr 2024 10:55:18 -0600 Subject: [PATCH 085/388] clean up comment --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index ec55b53fa0b..42b76723ff6 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -909,7 +909,7 @@ subroutine calc_edge_quantities(block, err) endif ! if edge of grounded ice end do - ! zero gradients at boundaries of the mesh + ! zero gradients at edges that are marked as no flux. These should be applied at boundaries of the mesh. do iEdge = 1, nEdges if (waterFluxMask(iEdge) == 2) then hydropotentialBaseSlopeNormal(iEdge) = 0.0_RKIND From 304eb23b19460affc346625cc7bbf0d445de0ef2 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 3 Apr 2024 11:19:23 -0600 Subject: [PATCH 086/388] Define SMALL_GRADPHI Define private module variable SMALL_GRADPHI, the minimum allowed gradMagPhiEdge or gradMagPhiBaseEdge allowed before all dependent variables are zeroed out. Replaces previous arbitrary threshold of 0.01 --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 42b76723ff6..4067e295143 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -56,7 +56,8 @@ module li_subglacial_hydro ! Private module variables ! !-------------------------------------------------------------------- - +! Minimum gradMagPhiBaseEdge and gradMagPhiEdge allowed before all dependent variables are zeroed out +real(kind=RKIND), parameter :: SMALL_GRADPHI = 1.0e-6_RKIND !*********************************************************************** contains @@ -1000,7 +1001,7 @@ subroutine calc_edge_quantities(block, err) if (conduc_coeff_drowned > 0.0_RKIND) then ! Use a thickness weighted conductivity coeff. when water thickness exceeds bump height do iEdge = 1, nEdges - if (gradMagPhiBaseEdge(iEdge) < 0.01_RKIND) then + if (gradMagPhiBaseEdge(iEdge) < SMALL_GRADPHI) then effectiveConducEdge(iEdge) = 0.0_RKIND else conduc_coeff_wtd = (conduc_coeff * min(waterThicknessEdge(iEdge), bedRoughMax) + & @@ -1014,7 +1015,7 @@ subroutine calc_edge_quantities(block, err) else do iEdge = 1, nEdges ! Just use a single conductivity coeff. - if (gradMagPhiBaseEdge(iEdge) < 0.01_RKIND) then + if (gradMagPhiBaseEdge(iEdge) < SMALL_GRADPHI) then effectiveConducEdge(iEdge) = 0.0_RKIND else effectiveConducEdge(iEdge) = conduc_coeff * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) *& @@ -1809,7 +1810,7 @@ subroutine update_channel(block, err) ! Calculate terms needed for opening (melt) rate - where(gradMagPhiEdge < 0.01_RKIND) + where(gradMagPhiEdge < SMALL_GRADPHI) channelDischarge(:) = 0.0_RKIND elsewhere channelDischarge = -1.0_RKIND * Kc * channelArea**alpha_c * gradMagPhiEdge**(beta_c - 2.0_RKIND) * & @@ -1838,7 +1839,7 @@ subroutine update_channel(block, err) channelVelocity = channelDischarge / (channelArea + 1.0e-12_RKIND) ! diffusivity used only to limit channel dt right now - where(gradMagPhiEdge < 0.01_RKIND) + where(gradMagPhiEdge < SMALL_GRADPHI) channelDiffusivity = 0.0_RKIND elsewhere channelDiffusivity = abs(rho_water * gravity * channelArea * & From 5bb861056c5157d61ba695a2289bf4e586166cb7 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 18 Oct 2023 15:43:31 -0700 Subject: [PATCH 087/388] totalGroundingLineDischargeCell/Edge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds field totalGroundingLineDischargeCell – the total grounding line discharge, extrapolated from the grounding line edge to the adjacent ocean cell. Also introduces totalGroundingLineDischargeEdge – the total grounding line discharge at each edge. For use with MPAS-Ocean --- .../src/Registry_subglacial_hydro.xml | 8 ++- .../mode_forward/mpas_li_subglacial_hydro.F | 63 +++++++++++++++---- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index b70e885eb59..5aa5d66e7bb 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -230,7 +230,11 @@ description="time step length limited by pressure equation scheme in subglacial hydrology system" /> - + + + - + diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index cffd631f00b..88c2e4f4cd3 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1718,7 +1718,6 @@ subroutine update_channel(block, err) ! local variables !----------------------------------------------------------------- ! Pools pointers -!! type (mpas_pool_type), pointer :: geometryPool type (mpas_pool_type), pointer :: hydroPool type (mpas_pool_type), pointer :: meshPool type (mpas_pool_type), pointer :: velocityPool @@ -1730,7 +1729,8 @@ subroutine update_channel(block, err) real (kind=RKIND), pointer :: rhoi real (kind=RKIND), pointer :: config_SGH_incipient_channel_width logical, pointer :: config_SGH_include_pressure_melt - + real (kind=RKIND), pointer :: config_SGH_bed_roughness_max + real (kind=RKIND), pointer :: config_sea_level real (kind=RKIND), dimension(:), pointer :: channelArea real (kind=RKIND), dimension(:), pointer :: channelMelt real (kind=RKIND), dimension(:), pointer :: channelPressureFreeze @@ -1747,26 +1747,37 @@ subroutine update_channel(block, err) real (kind=RKIND), dimension(:), pointer :: channelEffectivePressure real (kind=RKIND), dimension(:), pointer :: effectivePressure real (kind=RKIND), dimension(:), pointer :: channelDiffusivity + real (kind=RKIND), dimension(:), pointer :: waterThickness + real (kind=RKIND), dimension(:), pointer :: waterPressure + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro + real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeCell + real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeEdge + real (kind=RKIND), dimension(:), pointer :: dvEdge + real (kind=RKIND), dimension(:), pointer :: bedTopography integer, dimension(:), pointer :: waterFluxMask integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:), pointer :: edgeMask real (kind=RKIND), dimension(:,:), pointer :: flowParamA integer, dimension(:,:), pointer :: cellsOnEdge integer, pointer :: nVertLevels - - integer, pointer :: nEdgesSolve + real (kind=RKIND), pointer :: config_SGH_max_chnl_lake_depth + character (len=StrKIND), pointer :: config_SGH_inhibit_chnls_on_lakes + real (kind=RKIND), dimension(:), pointer :: xCell + real (kind=RKIND), dimension(:), pointer :: yCell + real (kind=RKIND), dimension(:), pointer :: xEdge + real (kind=RKIND), dimension(:), pointer :: yEdge + integer, dimension(:), pointer :: cellMask + integer, pointer :: nEdgesSolve, nEdges integer :: iEdge, cell1, cell2 - err = 0 ! Get pools things call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) -! call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) - + call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_conduc_coeff', Kc) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_alpha', alpha_c) @@ -1774,10 +1785,8 @@ subroutine update_channel(block, err) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_creep_coefficient', creep_coeff) call mpas_pool_get_config(liConfigs, 'config_SGH_incipient_channel_width', config_SGH_incipient_channel_width) call mpas_pool_get_config(liConfigs, 'config_SGH_include_pressure_melt', config_SGH_include_pressure_melt) - call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels) - call mpas_pool_get_array(hydroPool, 'channelArea', channelArea) call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) call mpas_pool_get_array(hydroPool, 'channelPressureFreeze', channelPressureFreeze) @@ -1799,7 +1808,15 @@ subroutine update_channel(block, err) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(hydroPool, 'channelDiffusivity', channelDiffusivity) call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - + call mpas_pool_get_array(meshPool, 'xCell', xCell) + call mpas_pool_get_array(meshPool, 'yCell', yCell) + call mpas_pool_get_array(meshPool, 'xEdge', xEdge) + call mpas_pool_get_array(meshPool, 'yEdge', yEdge) + call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) + call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) + call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeCell', totalGroundingLineDischargeCell) + call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeEdge', totalGroundingLineDischargeEdge) + call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) ! Calculate terms needed for opening (melt) rate where(gradMagPhiEdge < 0.01_RKIND) @@ -1867,9 +1884,31 @@ subroutine update_channel(block, err) channelOpeningRate = 0.0_RKIND channelClosingRate = 0.0_RKIND end where + channelChangeRate = channelOpeningRate - channelClosingRate - - + + totalGroundingLineDischargeCell(:) = 0.0_RKIND + totalGroundingLineDischargeEdge(:) = 0.0_RKIND + do iEdge = 1, nEdgesSolve + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + + if (hydroMarineMarginMask(iEdge) == 1) then + ! We are looking for edges with 1 cell grounded ice and the + ! other cell floating ice or open ocean + if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & + (li_mask_is_floating_ice(cellMask(cell2)) .or. & + ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then + totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) +abs( waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell2) = totalGroundingLineDischargeCell(cell2) + totalGroundingLineDischargeEdge(iEdge) + elseif ( (li_mask_is_grounded_ice(cellMask(cell2))) .and. & + (li_mask_is_floating_ice(cellMask(cell1)) .or. & + ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then + totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) + abs(waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell1) = totalGroundingLineDischargeCell(cell1) + totalGroundingLineDischargeEdge(iEdge) + endif + endif + enddo !-------------------------------------------------------------------- end subroutine update_channel From 7cfb3dd7d6fc8d2b9b1c85f06d61c2481fa5b963 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 3 Apr 2024 19:06:13 -0700 Subject: [PATCH 088/388] Add mask updates between calving routines Update masks before mask calving, between mask calving and iceberg removal, and between iceberg removal and small island removal. --- .../src/mode_forward/mpas_li_calving.F | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index a86612ad00e..1df2391cdb2 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -305,6 +305,12 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) endif + call mpas_pool_get_subpool(domain % blocklist % structs, 'geometry', geometryPool) + call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(domain % blocklist % structs, 'velocity', velocityPool) + + call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) + ! Consider mask calving as a possible additional step ! Mask calving can occur by itself or in conjunction with a physical calving law if (config_apply_calving_mask) then @@ -312,15 +318,20 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) err = ior(err, err_tmp) endif + call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) + ! now also remove any icebergs call remove_icebergs(domain) + call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) + ! Final operations after calving has been applied, including removal ! of small islands block => domain % blocklist do while (associated(block)) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) @@ -350,7 +361,6 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) endif ! config_print_calving_info ! Update mask and geometry - call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) err = ior(err, err_tmp) call li_update_geometry(geometryPool) From 57a370e11206e87d7a27d5d253147fd58d61c4dd Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 27 Mar 2024 09:04:28 -0700 Subject: [PATCH 089/388] Move totalGroundingLineDischargeCell/Edge to subroutine This commit establishes a separate subroutine for calculating totalGroundingLineDischargeCell/Edge --- .../mode_forward/mpas_li_subglacial_hydro.F | 129 +++++++++++++++--- 1 file changed, 107 insertions(+), 22 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 88c2e4f4cd3..3da17bdcd98 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -551,6 +551,21 @@ subroutine li_SGH_solve(domain, err) call mpas_timer_stop("halo updates") endif + ! ============= + ! Calculate total grounding line discharges + ! ============= + block => domain % blocklist + do while (associated(block)) + + call calc_gl_totals(block, err_tmp) + err = ior(err, err_tmp) + + block => block % next + end do + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'totalGroundingLineDischargeCell') + call mpas_dmpar_field_halo_exch(domain, 'totalGroundingLineDischargeEdge') + call mpas_timer_stop("halo updates") ! ============= ! Update water layer thickness @@ -1887,28 +1902,6 @@ subroutine update_channel(block, err) channelChangeRate = channelOpeningRate - channelClosingRate - totalGroundingLineDischargeCell(:) = 0.0_RKIND - totalGroundingLineDischargeEdge(:) = 0.0_RKIND - do iEdge = 1, nEdgesSolve - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) - - if (hydroMarineMarginMask(iEdge) == 1) then - ! We are looking for edges with 1 cell grounded ice and the - ! other cell floating ice or open ocean - if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & - (li_mask_is_floating_ice(cellMask(cell2)) .or. & - ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then - totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) +abs( waterFlux(iEdge) * dvEdge(iEdge)) - totalGroundingLineDischargeCell(cell2) = totalGroundingLineDischargeCell(cell2) + totalGroundingLineDischargeEdge(iEdge) - elseif ( (li_mask_is_grounded_ice(cellMask(cell2))) .and. & - (li_mask_is_floating_ice(cellMask(cell1)) .or. & - ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then - totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) + abs(waterFlux(iEdge) * dvEdge(iEdge)) - totalGroundingLineDischargeCell(cell1) = totalGroundingLineDischargeCell(cell1) + totalGroundingLineDischargeEdge(iEdge) - endif - endif - enddo !-------------------------------------------------------------------- end subroutine update_channel @@ -2310,4 +2303,96 @@ subroutine calc_hydro_mask(domain) !-------------------------------------------------------------------- end subroutine calc_hydro_mask +!*********************************************************************** +! +! routine calc_gl_total +! +!> \brief Calculate total grounding line discharge on edges and +! adjacent cells +!> \author Alex Hager +!> \date 27 March 2024 +!> \details +!----------------------------------------------------------------------- + subroutine calc_gl_totals(block, err) + + !----------------------------------------------------------------- + ! input variables + !----------------------------------------------------------------- + + !----------------------------------------------------------------- + ! input/output variables + !----------------------------------------------------------------- + type (block_type), intent(inout) :: block !< Input/Output: block object + + !----------------------------------------------------------------- + ! output variables + !----------------------------------------------------------------- + integer, intent(out) :: err !< Output: error flag + + !----------------------------------------------------------------- + !----------------------------------------------------------------- + ! output variables + !----------------------------------------------------------------- + + !----------------------------------------------------------------- + ! local variables + !----------------------------------------------------------------- + type (mpas_pool_type), pointer :: hydroPool + type (mpas_pool_type), pointer :: geometryPool + type (mpas_pool_type), pointer :: meshPool + + real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeCell + real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeEdge + real (kind=RKIND), dimension(:), pointer :: bedTopography + real (kind=RKIND), dimension(:), pointer :: channelDischarge + real (kind=RKIND), dimension(:), pointer :: waterFlux + real (kind=RKIND), dimension(:), pointer :: dvEdge + integer iEdge, cell1, cell2 + integer, pointer :: nEdgesSolve + integer, dimension(:,:), pointer :: cellsOnEdge + integer, dimension(:), pointer :: hydroMarineMarginMask + integer, dimension(:), pointer :: cellMask + real (kind=RKIND), pointer :: config_sea_level + + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) + call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) + call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + + call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeCell', totalGroundingLineDischargeCell) + call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeEdge', totalGroundingLineDischargeEdge) + call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) + call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) + call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) + call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) + call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) + call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) + call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) + call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) + call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) + + totalGroundingLineDischargeCell(:) = 0.0_RKIND + totalGroundingLineDischargeEdge(:) = 0.0_RKIND + + do iEdge = 1, nEdgesSolve + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + + if (hydroMarineMarginMask(iEdge) == 1) then + ! We are looking for edges with 1 cell grounded ice and the + ! other cell floating ice or open ocean + if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & + (li_mask_is_floating_ice(cellMask(cell2)) .or. & + ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then + totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) +abs( waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell2) = totalGroundingLineDischargeCell(cell2) + totalGroundingLineDischargeEdge(iEdge) + elseif ( (li_mask_is_grounded_ice(cellMask(cell2))) .and. & + (li_mask_is_floating_ice(cellMask(cell1)) .or. & + ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then + totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) + abs(waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell1) = totalGroundingLineDischargeCell(cell1) + totalGroundingLineDischargeEdge(iEdge) + endif + endif + enddo + end subroutine calc_gl_totals + end module li_subglacial_hydro From 0194a2b1ea565e95765fd741d95def019414c3b6 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Apr 2024 08:18:19 -0700 Subject: [PATCH 090/388] pam_debug update --- .../eam/src/physics/crm/pam/pam_debug.h | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_debug.h b/components/eam/src/physics/crm/pam/pam_debug.h index 937d18cf154..2d3dc1efb89 100644 --- a/components/eam/src/physics/crm/pam/pam_debug.h +++ b/components/eam/src/physics/crm/pam/pam_debug.h @@ -27,28 +27,32 @@ inline void pam_debug_init( pam::PamCoupler &coupler ) { auto nens = coupler.get_option("ncrms"); //------------------------------------------------------------------------------------------------ dm_device.register_and_allocate("debug_save_temp", "saved temp for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); + dm_device.register_and_allocate("debug_save_rhod", "saved rhod for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhov", "saved rhov for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhoc", "saved rhoc for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_rhoi", "saved rhoi for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_uvel", "saved uvel for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); dm_device.register_and_allocate("debug_save_wvel", "saved wvel for debug", {nz,ny,nx,nens}, {"z","y","x","nens"} ); auto debug_save_temp = dm_device.get("debug_save_temp"); + auto debug_save_rhod = dm_device.get("debug_save_rhod"); auto debug_save_rhov = dm_device.get("debug_save_rhov"); auto debug_save_rhoc = dm_device.get("debug_save_rhoc"); auto debug_save_rhoi = dm_device.get("debug_save_rhoi"); auto debug_save_uvel = dm_device.get("debug_save_uvel"); auto debug_save_wvel = dm_device.get("debug_save_wvel"); //------------------------------------------------------------------------------------------------ - auto temp = dm_device.get("temp"); - auto rhov = dm_device.get("water_vapor"); - auto rhoc = dm_device.get("cloud_water"); - auto rhoi = dm_device.get("ice"); - auto uvel = dm_device.get("uvel"); - auto wvel = dm_device.get("wvel"); + auto temp = dm_device.get("temp"); + auto rhod = dm_device.get("density_dry"); + auto rhov = dm_device.get("water_vapor"); + auto rhoc = dm_device.get("cloud_water"); + auto rhoi = dm_device.get("ice"); + auto uvel = dm_device.get("uvel"); + auto wvel = dm_device.get("wvel"); //------------------------------------------------------------------------------------------------ parallel_for("copy data to saved debug variables", SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); + debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); debug_save_rhov(k,j,i,iens) = rhov(k,j,i,iens); debug_save_rhoc(k,j,i,iens) = rhoc(k,j,i,iens); debug_save_rhoi(k,j,i,iens) = rhoi(k,j,i,iens); @@ -69,12 +73,14 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { auto nz = coupler.get_option("crm_nz"); auto nens = coupler.get_option("ncrms"); auto temp = dm_device.get("temp"); + auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhoc = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice"); auto uvel = dm_device.get("uvel"); auto wvel = dm_device.get("wvel"); auto debug_save_temp = dm_device.get("debug_save_temp"); + auto debug_save_rhod = dm_device.get("debug_save_rhod"); auto debug_save_rhov = dm_device.get("debug_save_rhov"); auto debug_save_rhoc = dm_device.get("debug_save_rhoc"); auto debug_save_rhoi = dm_device.get("debug_save_rhoi"); @@ -90,18 +96,21 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { auto phis = input_phis(iens)/grav; // Check for NaNs const auto is_nan_t_atm = isnan( temp(k,j,i,iens) ); + const auto is_nan_d_atm = isnan( rhod(k,j,i,iens) ); const auto is_nan_q_atm = isnan( rhov(k,j,i,iens) ); - if ( is_nan_t_atm || is_nan_q_atm ) { + if ( is_nan_t_atm || is_nan_q_atm || is_nan_d_atm ) { auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), + rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), uvel(k,j,i,iens), wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), debug_save_rhoi(k,j,i,iens), @@ -111,18 +120,21 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { } // Check for negative values const auto is_neg_t_atm = temp(k,j,i,iens)<0; + const auto is_neg_d_atm = rhod(k,j,i,iens)<0; const auto is_neg_q_atm = rhov(k,j,i,iens)<0; - if ( is_neg_t_atm || is_neg_q_atm ) { + if ( is_neg_t_atm || is_neg_q_atm || is_neg_d_atm ) { auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), + rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), uvel(k,j,i,iens), wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), debug_save_rhoi(k,j,i,iens), @@ -133,15 +145,17 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { // Check for low temperature const auto is_low_t = temp(k,j,i,iens)<100; if ( is_low_t ) { - printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), + rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), uvel(k,j,i,iens), wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), debug_save_rhoi(k,j,i,iens), @@ -153,15 +167,17 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { const auto is_large_pos_w = wvel(k,j,i,iens)> 40; const auto is_large_neg_w = wvel(k,j,i,iens)<-40; if ( is_large_pos_w || is_large_neg_w ) { - printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), + rhod(k,j,i,iens), rhov(k,j,i,iens), rhoc(k,j,i,iens), rhoi(k,j,i,iens), uvel(k,j,i,iens), wvel(k,j,i,iens), debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), debug_save_rhov(k,j,i,iens), debug_save_rhoc(k,j,i,iens), debug_save_rhoi(k,j,i,iens), @@ -171,6 +187,7 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { } // update saved previous values debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); + debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); debug_save_rhov(k,j,i,iens) = rhov(k,j,i,iens); debug_save_rhoc(k,j,i,iens) = rhoc(k,j,i,iens); debug_save_rhoi(k,j,i,iens) = rhoi(k,j,i,iens); From 39da4a6344b42b04ab49036dfed78770f07b79b6 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 5 Apr 2024 14:07:12 -0600 Subject: [PATCH 091/388] Cleanup PR This commit makes minor formatting adjustments to address comments in PR review. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 4067e295143..e8fa19ff51f 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -56,8 +56,8 @@ module li_subglacial_hydro ! Private module variables ! !-------------------------------------------------------------------- -! Minimum gradMagPhiBaseEdge and gradMagPhiEdge allowed before all dependent variables are zeroed out -real(kind=RKIND), parameter :: SMALL_GRADPHI = 1.0e-6_RKIND + ! Minimum gradMagPhiBaseEdge and gradMagPhiEdge allowed before all dependent variables are zeroed out + real(kind=RKIND), parameter :: SMALL_GRADPHI = 1.0e-6_RKIND !*********************************************************************** contains @@ -773,7 +773,6 @@ subroutine calc_edge_quantities(block, err) integer, dimension(:), pointer :: edgeMask integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:,:), pointer :: verticesOnEdge - integer, dimension(:,:), pointer :: cellsOnVertex integer, dimension(:,:), pointer :: baryCellsOnVertex real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex real (kind=RKIND), pointer :: alpha, beta @@ -1019,7 +1018,7 @@ subroutine calc_edge_quantities(block, err) effectiveConducEdge(iEdge) = 0.0_RKIND else effectiveConducEdge(iEdge) = conduc_coeff * waterThicknessEdge(iEdge)**(alpha-1.0_RKIND) *& - gradMagPhiBaseEdge(iEdge)**(beta - 2.0_RKIND) + gradMagPhiBaseEdge(iEdge)**(beta - 2.0_RKIND) endif enddo endif @@ -2192,7 +2191,8 @@ end subroutine ocean_connection_N !> \author Matt Hoffman !> \date 24 October 2022 !> \details -!> This routine calculates a mask of the boundaries of the active hydrology domain +!> This routine calculates a mask of the boundaries of the active hydrology domain. +!> If there no waterFluxMask around domain boundaries, then calc_hydro_mask creates one. !----------------------------------------------------------------------- subroutine calc_hydro_mask(domain) @@ -2291,7 +2291,7 @@ subroutine calc_hydro_mask(domain) end do if (wfmWarning == 1) then - call mpas_log_write('WARNING: Changing waterFluxMask to enforce no-flow conditions at domain boundaries') + call mpas_log_write('Changing waterFluxMask to enforce no-flow conditions at domain boundaries', MPAS_LOG_WARN) endif call mpas_timer_start("halo updates") call mpas_dmpar_field_halo_exch(domain, 'hydroMarineMarginMask') From c3ad2365025dc7ff8f86b26bdda0ac9ce7a9374b Mon Sep 17 00:00:00 2001 From: Matt Hoffman Date: Fri, 5 Apr 2024 14:20:46 -0600 Subject: [PATCH 092/388] Update components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index e8fa19ff51f..76fdc8c0432 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2192,7 +2192,7 @@ end subroutine ocean_connection_N !> \date 24 October 2022 !> \details !> This routine calculates a mask of the boundaries of the active hydrology domain. -!> If there no waterFluxMask around domain boundaries, then calc_hydro_mask creates one. +!> If there is no waterFluxMask set around domain boundaries, then calc_hydro_mask creates one. !----------------------------------------------------------------------- subroutine calc_hydro_mask(domain) From 3ed937dfd495b81916fcdf391d77fa38c40b7f06 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 5 Apr 2024 15:34:11 -0600 Subject: [PATCH 093/388] Clean up PR Makes a series of minor changes cleaning up the PR in accordance to review comments. Biggest change is the removal of superfluous variable totalGroundingLineDischargeEdge. --- .../src/Registry_subglacial_hydro.xml | 3 - .../mode_forward/mpas_li_subglacial_hydro.F | 60 ++++--------------- 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 5aa5d66e7bb..9199facf741 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -232,8 +232,6 @@ description="time step used for evolving subglacial hydrology system" /> - @@ -267,7 +265,6 @@ description="rate of channel melt production within each cell, averaged over cell area" /> - diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 3da17bdcd98..3a6a36a698e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1744,8 +1744,6 @@ subroutine update_channel(block, err) real (kind=RKIND), pointer :: rhoi real (kind=RKIND), pointer :: config_SGH_incipient_channel_width logical, pointer :: config_SGH_include_pressure_melt - real (kind=RKIND), pointer :: config_SGH_bed_roughness_max - real (kind=RKIND), pointer :: config_sea_level real (kind=RKIND), dimension(:), pointer :: channelArea real (kind=RKIND), dimension(:), pointer :: channelMelt real (kind=RKIND), dimension(:), pointer :: channelPressureFreeze @@ -1762,27 +1760,13 @@ subroutine update_channel(block, err) real (kind=RKIND), dimension(:), pointer :: channelEffectivePressure real (kind=RKIND), dimension(:), pointer :: effectivePressure real (kind=RKIND), dimension(:), pointer :: channelDiffusivity - real (kind=RKIND), dimension(:), pointer :: waterThickness - real (kind=RKIND), dimension(:), pointer :: waterPressure - real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro - real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeCell - real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeEdge - real (kind=RKIND), dimension(:), pointer :: dvEdge - real (kind=RKIND), dimension(:), pointer :: bedTopography integer, dimension(:), pointer :: waterFluxMask integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:), pointer :: edgeMask real (kind=RKIND), dimension(:,:), pointer :: flowParamA integer, dimension(:,:), pointer :: cellsOnEdge integer, pointer :: nVertLevels - real (kind=RKIND), pointer :: config_SGH_max_chnl_lake_depth - character (len=StrKIND), pointer :: config_SGH_inhibit_chnls_on_lakes - real (kind=RKIND), dimension(:), pointer :: xCell - real (kind=RKIND), dimension(:), pointer :: yCell - real (kind=RKIND), dimension(:), pointer :: xEdge - real (kind=RKIND), dimension(:), pointer :: yEdge - integer, dimension(:), pointer :: cellMask - integer, pointer :: nEdgesSolve, nEdges + integer, pointer :: nEdgesSolve integer :: iEdge, cell1, cell2 err = 0 @@ -1792,7 +1776,6 @@ subroutine update_channel(block, err) call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) - call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) call mpas_pool_get_config(liConfigs, 'config_ice_density', rhoi) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_conduc_coeff', Kc) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_alpha', alpha_c) @@ -1800,8 +1783,8 @@ subroutine update_channel(block, err) call mpas_pool_get_config(liConfigs, 'config_SGH_chnl_creep_coefficient', creep_coeff) call mpas_pool_get_config(liConfigs, 'config_SGH_incipient_channel_width', config_SGH_incipient_channel_width) call mpas_pool_get_config(liConfigs, 'config_SGH_include_pressure_melt', config_SGH_include_pressure_melt) - call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) call mpas_pool_get_dimension(meshPool, 'nVertLevels', nVertLevels) + call mpas_pool_get_dimension(meshPool, 'nEdgesSolve', nEdgesSolve) call mpas_pool_get_array(hydroPool, 'channelArea', channelArea) call mpas_pool_get_array(hydroPool, 'channelMelt', channelMelt) call mpas_pool_get_array(hydroPool, 'channelPressureFreeze', channelPressureFreeze) @@ -1823,17 +1806,8 @@ subroutine update_channel(block, err) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(hydroPool, 'channelDiffusivity', channelDiffusivity) call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - call mpas_pool_get_array(meshPool, 'xCell', xCell) - call mpas_pool_get_array(meshPool, 'yCell', yCell) - call mpas_pool_get_array(meshPool, 'xEdge', xEdge) - call mpas_pool_get_array(meshPool, 'yEdge', yEdge) - call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) - call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) - call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeCell', totalGroundingLineDischargeCell) - call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeEdge', totalGroundingLineDischargeEdge) - call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) + ! Calculate terms needed for opening (melt) rate - where(gradMagPhiEdge < 0.01_RKIND) channelDischarge(:) = 0.0_RKIND elsewhere @@ -2307,11 +2281,11 @@ end subroutine calc_hydro_mask ! ! routine calc_gl_total ! -!> \brief Calculate total grounding line discharge on edges and -! adjacent cells +!> \brief Calculate total grounding line discharge on +! adjacent ocean cell !> \author Alex Hager !> \date 27 March 2024 -!> \details +!> \details Find the total amount of freshwater entering the first ocean cell from the grounding line. !----------------------------------------------------------------------- subroutine calc_gl_totals(block, err) @@ -2342,7 +2316,6 @@ subroutine calc_gl_totals(block, err) type (mpas_pool_type), pointer :: meshPool real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeCell - real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeEdge real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: channelDischarge real (kind=RKIND), dimension(:), pointer :: waterFlux @@ -2352,6 +2325,7 @@ subroutine calc_gl_totals(block, err) integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:), pointer :: cellMask + real (kind=RKIND) :: totalGroundingLineDischargeEdge real (kind=RKIND), pointer :: config_sea_level call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) @@ -2359,7 +2333,6 @@ subroutine calc_gl_totals(block, err) call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeCell', totalGroundingLineDischargeCell) - call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeEdge', totalGroundingLineDischargeEdge) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) @@ -2371,25 +2344,18 @@ subroutine calc_gl_totals(block, err) call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) totalGroundingLineDischargeCell(:) = 0.0_RKIND - totalGroundingLineDischargeEdge(:) = 0.0_RKIND do iEdge = 1, nEdgesSolve cell1 = cellsOnEdge(1, iEdge) cell2 = cellsOnEdge(2, iEdge) if (hydroMarineMarginMask(iEdge) == 1) then - ! We are looking for edges with 1 cell grounded ice and the - ! other cell floating ice or open ocean - if ( (li_mask_is_grounded_ice(cellMask(cell1))) .and. & - (li_mask_is_floating_ice(cellMask(cell2)) .or. & - ((bedTopography(cell2) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell2)))) ) ) then - totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) +abs( waterFlux(iEdge) * dvEdge(iEdge)) - totalGroundingLineDischargeCell(cell2) = totalGroundingLineDischargeCell(cell2) + totalGroundingLineDischargeEdge(iEdge) - elseif ( (li_mask_is_grounded_ice(cellMask(cell2))) .and. & - (li_mask_is_floating_ice(cellMask(cell1)) .or. & - ((bedTopography(cell1) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(cell1)))) ) ) then - totalGroundingLineDischargeEdge(iEdge) = abs(channelDischarge(iEdge)) + abs(waterFlux(iEdge) * dvEdge(iEdge)) - totalGroundingLineDischargeCell(cell1) = totalGroundingLineDischargeCell(cell1) + totalGroundingLineDischargeEdge(iEdge) + if (li_mask_is_grounded_ice(cellMask(cell1))) then + totalGroundingLineDischargeEdge = abs(channelDischarge(iEdge)) +abs( waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell2) = totalGroundingLineDischargeCell(cell2) + totalGroundingLineDischargeEdge + elseif (li_mask_is_grounded_ice(cellMask(cell2))) then + totalGroundingLineDischargeEdge = abs(channelDischarge(iEdge)) + abs(waterFlux(iEdge) * dvEdge(iEdge)) + totalGroundingLineDischargeCell(cell1) = totalGroundingLineDischargeCell(cell1) + totalGroundingLineDischargeEdge endif endif enddo From f2325d3849b51cbc62715afcdcba3b10f7bb2b34 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 5 Apr 2024 16:52:36 -0600 Subject: [PATCH 094/388] dist. and chnl. grounding line totals Calculates the distributed and channelized contributions to totalGroundingLineDischargeCell --- .../src/Registry_subglacial_hydro.xml | 8 +++++-- .../mode_forward/mpas_li_subglacial_hydro.F | 21 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 9199facf741..61d8fa7f681 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -229,10 +229,14 @@ + description="time step used for evolving subglacial hydrology system" /> + + description="total (channel + dist.) discharge across the grounding line, extrapolated from edge to adjacent ungrounded cell. Values from all edges are summed if multiple grounding line edges border a single ungrounded cell" /> + Date: Mon, 8 Apr 2024 14:41:54 -0700 Subject: [PATCH 095/388] Improve remove_small_islands Remove small islands that are one or two grounded cells with or without a one-cell-wide floating dynamic ice shelf. --- .../src/mode_forward/mpas_li_calving.F | 210 +++++++++++++----- 1 file changed, 158 insertions(+), 52 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 1df2391cdb2..7d4b7799520 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -320,6 +320,10 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) + call remove_small_islands(meshPool, geometryPool, domain) + + call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) + ! now also remove any icebergs call remove_icebergs(domain) @@ -336,7 +340,6 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) - call remove_small_islands(meshPool, geometryPool) ! In data calving mode we just calculate what should be calved but don't actually calve it. ! So set thickness back to original value. if (config_data_calving) then @@ -1023,20 +1026,23 @@ end subroutine floating_calving ! routine remove_small_islands ! !> \brief Remove very small islands that lead to velocity solver problems -!> \author Matthew Hoffman -!> \date Summer 2018 +!> \author Matthew Hoffman, Trevor Hillebrand +!> \date Summer 2018, re-written Apr 2024 !> \details This routine finds and eliminates very small islands that lead to !> unrealistic velocities in the Albany velocity solver. Specifically, this -!> finds one- and two-cell masses of ice that are surrounded by open ocean -!> and eliminates them by sending them to the calving flux. +!> finds one- and two-cell masses of grounded ice that are surrounded by dynamic +!> floating ice ice shelves ≥1 cell wide. It eliminates the dynamic cells +!> (both grounded and floating) in these islands by sending them to the +!> and then cleans up stranded non-dynamic cells using a flood-fill routine. !----------------------------------------------------------------------- - subroutine remove_small_islands(meshPool, geometryPool) + subroutine remove_small_islands(meshPool, geometryPool, domain) type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: Geometry pool + type (domain_type), intent(inout) :: domain !< Input/Output: domain object + type (mpas_pool_type), pointer :: scratchPool logical, pointer :: config_remove_small_islands - real(kind=RKIND), pointer :: config_sea_level real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine) real (kind=RKIND), dimension(:), pointer :: calvingThicknessFromThreshold ! thickness of ice that calves (computed in this subroutine) real (kind=RKIND), dimension(:), pointer :: thickness @@ -1044,73 +1050,173 @@ subroutine remove_small_islands(meshPool, geometryPool) integer, dimension(:), pointer :: cellMask integer, dimension(:,:), pointer :: cellsOnCell ! list of cells that neighbor each cell integer, dimension(:), pointer :: nEdgesOnCell ! number of cells that border each cell - integer, pointer :: nCellsSolve - integer :: iCell, jCell, n, nIceNeighbors, nIceNeighbors2, neighborWithIce - integer :: nOpenOceanNeighbors, nOpenOceanNeighbors2 + integer, pointer :: nCells, maxEdges + logical :: removeIsland + integer :: iCell, jCell, kCell, m, n, count + integer :: nGroundedNeighbors, nGroundedNeighborsJCell + integer, dimension(:), allocatable :: connectedCellsList + integer, dimension(:), allocatable :: islandMask + type (field1dInteger), pointer :: seedMaskField + type (field1dInteger), pointer :: growMaskField + integer, dimension(:), pointer :: seedMask, growMask !masks to pass to flood-fill routine call mpas_pool_get_config(liConfigs, 'config_remove_small_islands', config_remove_small_islands) if (.not. config_remove_small_islands) then return ! skip this entire routine if disabled endif - call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) - call mpas_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve) + call mpas_pool_get_subpool(domain % blocklist % structs, 'scratch', scratchPool) + + call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + call mpas_pool_get_dimension(meshPool, 'maxEdges', maxEdges) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_array(geometryPool, 'calvingThickness', calvingThickness) call mpas_pool_get_array(geometryPool, 'calvingThicknessFromThreshold', calvingThicknessFromThreshold) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) - call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) - do iCell = 1, nCellsSolve - if (li_mask_is_ice(cellMask(iCell))) then ! might as well do for both grounded or floating - ! (1 or 2 cell floating masses are icebergs) - nIceNeighbors = 0 - nOpenOceanNeighbors = 0 + allocate(connectedCellsList((maxEdges+1)**2), & + islandMask(nCells+1)) + + islandMask(:) = 0 + + ! Allocate scratch fields for flood-fill + call mpas_pool_get_field(scratchPool, 'seedMask', seedMaskField) + call mpas_allocate_scratch_field(seedMaskField, single_block_in = .true.) + seedMask => seedMaskField % array + seedMask(:) = 0 + + call mpas_pool_get_field(scratchPool, 'growMask', growMaskField) + call mpas_allocate_scratch_field(growMaskField, single_block_in = .true.) + growMask => growMaskField % array + growMask(:) = 0 + + ! Loop over cells to find one- and two-cell regions of grounded ice, + ! which are potentially islands that need to be removed. + do iCell = 1, nCells + if (li_mask_is_grounded_ice(cellMask(iCell))) then + + nGroundedNeighbors = 0 + ! Count grounded neighbors do n = 1, nEdgesOnCell(iCell) jCell = cellsOnCell(n, iCell) - if (li_mask_is_ice(cellMask(jCell))) then - nIceNeighbors = nIceNeighbors + 1 - neighborWithIce = jCell + if (li_mask_is_grounded_ice(cellMask(jCell))) then + nGroundedNeighbors = nGroundedNeighbors + 1 endif - if (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) then - nOpenOceanNeighbors = nOpenOceanNeighbors + 1 + nGroundedNeighborsJCell = 0 + ! If the neighbor contains dynamic ice, check whether + ! it has other grounded neighbors. If it does, then we + ! will not consider this an island. + if (li_mask_is_dynamic_ice(cellMask(jCell))) then + do m = 1, nEdgesOnCell(jCell) + kCell = cellsOnCell(m, jCell) + if (li_mask_is_grounded_ice(cellMask(kCell))) then + nGroundedNeighborsJCell = nGroundedNeighborsJCell + 1 + endif + enddo + endif + ! If this grounded cell is dynamically connected to 1 or + ! fewer other grounded cells, then it should potentially + ! be removed. If its dynamic neighbors have other grounded + ! neighbors, then it is not an island. + if ( (nGroundedNeighborsJCell .le. 1) .and. & + (nGroundedNeighbors .le. 1) ) then + islandMask(iCell) = 1 + else + islandMask(iCell) = 0 endif enddo - if ((nIceNeighbors == 0) .and. (nOpenOceanNeighbors == nEdgesOnCell(iCell))) then - ! If this is a single cell of ice surrounded by open ocean, kill this location + endif + enddo + + ! Determine whether to remove each island. First, make a list of the + ! dynamic neighbors of the cells in islandMask. If the grounded island + ! cell has a grounded neighbour, add that neighbor's dynamic neighbors + ! to the list. Then, check that all the dynamic neighbors of the cells + ! in the list are also in the list. If so, then this is considered an + ! island and is removed. If not, then leave it alone. + do iCell = 1, nCells + connectedCellsList(:) = -1 + if (islandMask(iCell) == 1) then + removeIsland = .true. ! evalulated and updated below + ! Make a list of the grounded island cell and its + ! dynamic neighbors. + count = 1 + connectedCellsList(count) = iCell + do n = 1, nEdgesOnCell(iCell) + jCell = cellsOnCell(n, iCell) + if (li_mask_is_dynamic_ice(cellMask(jCell))) then + count = count + 1 + connectedCellsList(count) = jCell + endif + ! If there is a grounded neighbor, list its dynamic neighbors as well + if (li_mask_is_grounded_ice(cellMask(jCell))) then + do m = 1, nEdgesOnCell(jCell) + kCell = cellsOnCell(m, jCell) + if (li_mask_is_dynamic_ice(cellMask(kCell))) then + count = count + 1 + connectedCellsList(count) = kCell + endif + enddo + endif + enddo + ! Check that all the dynamic neighbors of neighbors are + ! in the list. If not, then do not remove the island. + do n = 1, (maxEdges+1)**2 + if (connectedCellsList(n) == -1) then + exit ! We've reached the end of the list. + else + jCell = connectedCellsList(n) + do m = 1, nEdgesOnCell(jCell) + kCell = cellsOnCell(m, jCell) + if ( li_mask_is_dynamic_ice(cellMask(kCell)) .and. & + (.not. any(connectedCellsList == kCell)) ) then + removeIsland = .false. + exit + endif + enddo + endif + enddo + ! Actually remove island + ! TODO: halo update needed? Would need to change logic. + if ( removeIsland ) then + do n = 1, count + calvingThickness(connectedCellsList(n)) = calvingThickness(connectedCellsList(n)) + & + thickness(connectedCellsList(n)) + calvingThicknessFromThreshold(connectedCellsList(n)) = & + calvingThicknessFromThreshold(connectedCellsList(n)) + thickness(connectedCellsList(n)) + thickness(connectedCellsList(n)) = 0.0_RKIND + enddo + endif + endif + enddo + + ! Clean up by removing non-dynamic ice that may have been left behind + ! after islands where removed. + where (li_mask_is_grounded_ice(cellMask)) + seedMask = 1 + end where + + where (li_mask_is_ice(cellMask)) + growMask = 1 + end where + + call mpas_log_write("***Cleaning up stranded cells after removing small islands***") + call li_flood_fill(seedMask, growMask, domain) + do iCell = 1, nCells + if (li_mask_is_floating_ice(cellMask(iCell)) .and. seedMask(iCell) == 0) then calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell) calvingThicknessFromThreshold(iCell) = calvingThicknessFromThreshold(iCell) + thickness(iCell) thickness(iCell) = 0.0_RKIND - elseif (nIceNeighbors == 1) then - ! check if this neighbor has any additional neighbors with ice - nIceNeighbors2 = 0 - nOpenOceanNeighbors2 = 0 - do n = 1, nEdgesOnCell(neighborWithIce) - jCell = cellsOnCell(n, neighborWithIce) - if (li_mask_is_ice(cellMask(jCell))) then - nIceNeighbors2 = nIceNeighbors2 + 1 - endif - if (.not. li_mask_is_ice(cellMask(jCell)) .and. bedTopography(jCell) < config_sea_level) then - nOpenOceanNeighbors2 = nOpenOceanNeighbors2 + 1 - endif - enddo - if ((nIceNeighbors2 == 1) .and. (nOpenOceanNeighbors2 == nEdgesOnCell(iCell)-1)) then - ! <- only neighbor with ice must have been iCell - ! kill both cells - calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell) - calvingThicknessFromThreshold(iCell) = calvingThicknessFromThreshold(iCell) + thickness(iCell) - thickness(iCell) = 0.0_RKIND - calvingThickness(neighborWithIce) = calvingThickness(neighborWithIce) + thickness(neighborWithIce) - calvingThicknessFromThreshold(neighborWithIce) = calvingThicknessFromThreshold(neighborWithIce) + thickness(neighborWithIce) - thickness(neighborWithIce) = 0.0_RKIND - endif - - endif ! check on nIceNeighbors + endif + enddo + call mpas_log_write("***Finished cleaning up after removing small islands***") - endif ! check if iCell has ice - end do ! loop over cells + deallocate(connectedCellsList, & + islandMask) + call mpas_deallocate_scratch_field(seedMaskField, single_block_in=.true.) + call mpas_deallocate_scratch_field(growMaskField, single_block_in=.true.) end subroutine remove_small_islands From 730931f76f3a17a9c2da0bad2407190707f377d3 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 9 Apr 2024 11:17:12 -0700 Subject: [PATCH 096/388] bug fix in pam_state --- .../eam/src/physics/crm/pam/pam_state.h | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index 3266899ba21..a34a867eb6e 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -144,7 +144,7 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { real2d hmean_temp ("hmean_temp" ,nz ,nens); real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions // initialize horizontal means - parallel_for(SimpleBounds<2>(nz,nens), YAKL_LAMBDA (int k, int iens) { + parallel_for(SimpleBounds<2>(nz+1,nens), YAKL_LAMBDA (int k, int iens) { hmean_pint(k,iens) = 0; if (k < nz) { hmean_pmid (k,iens) = 0; @@ -166,24 +166,42 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { atomicAdd( hmean_temp (k,iens), temp (k,j,i,iens) * r_nx_ny ); }); // calculate interface pressure from mid-level pressure - parallel_for(SimpleBounds<4>(nz+1,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int iens) { + // parallel_for(SimpleBounds<4>(nz+1,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int iens) { + parallel_for(SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k, int iens) { if (k == 0 ) { - real rho = rho_d(k ,j,i,iens)+rho_v(k ,j,i,iens); - real dz = zint(k+1,iens)-zint(k ,iens); + real rho = hmean_rho_d(k,iens)+hmean_rho_v(k,iens); + real dz = zint(k+1,iens)-zint(k,iens); hmean_pint(k,iens) = hmean_pmid(k ,iens) + grav*rho*dz/2; } else if (k == nz) { - real rho = rho_d(k-1,j,i,iens)+rho_v(k-1,j,i,iens); - real dz = zint(k ,iens)-zint(k-1,iens); + real rho = hmean_rho_d(k-1,iens)+hmean_rho_v(k-1,iens); + real dz = zint(k,iens)-zint(k-1,iens); hmean_pint(k,iens) = hmean_pmid(k-1,iens) - grav*rho*dz/2; } else { - real rhokm1 = rho_d(k-1,j,i,iens)+rho_v(k-1,j,i,iens); - real rhokm0 = rho_d(k ,j,i,iens)+rho_v(k ,j,i,iens); + real rhokm1 = hmean_rho_d(k-1,iens)+hmean_rho_v(k-1,iens);; + real rhokm0 = hmean_rho_d(k ,iens)+hmean_rho_v(k ,iens); real dzkm1 = zint(k ,iens)-zint(k-1,iens); real dzkm0 = zint(k+1,iens)-zint(k ,iens); hmean_pint(k,iens) = 0.5_fp * ( hmean_pmid(k-1,iens) - grav*rhokm1*dzkm1/2 + hmean_pmid(k ,iens) + grav*rhokm0*dzkm0/2 ); } }); + + auto &dm_host = coupler.get_data_manager_host_readonly(); + auto lat = dm_host.get("latitude" ).createDeviceCopy(); + auto lon = dm_host.get("longitude" ).createDeviceCopy(); + auto input_phis = dm_host.get("input_phis").createDeviceCopy(); + // check that interface pressure is reasonable + parallel_for(SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k, int iens) { + if ( hmean_pint(k,iens) < hmean_pmid(k,iens) ) { + auto phis = input_phis(iens)/grav; + printf("PAM-DEBUG bad-pint - k:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- pint:%8.2g pmid:%8.2g \n", + k,iens,lat(iens),lon(iens),phis, + hmean_pint(k,iens), + hmean_pmid(k,iens) + ); + } + }); + // set anelastic reference state from CRM horizontal mean parallel_for(SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k, int iens) { ref_presi(k,iens) = hmean_pint(k,iens); From b094fc0db0534982a3f52aadd2ba5466e09be4e7 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 9 Apr 2024 11:20:48 -0700 Subject: [PATCH 097/388] pam_debug updates --- .../eam/src/physics/crm/pam/pam_debug.h | 73 ++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_debug.h b/components/eam/src/physics/crm/pam/pam_debug.h index 2d3dc1efb89..43d2b5bf4f5 100644 --- a/components/eam/src/physics/crm/pam/pam_debug.h +++ b/components/eam/src/physics/crm/pam/pam_debug.h @@ -142,32 +142,31 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { debug_save_wvel(k,j,i,iens) ); } - // Check for low temperature - const auto is_low_t = temp(k,j,i,iens)<100; - if ( is_low_t ) { - printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - nstep,id,k,i,iens,lat(iens),lon(iens),phis, - temp(k,j,i,iens), - rhod(k,j,i,iens), - rhov(k,j,i,iens), - rhoc(k,j,i,iens), - rhoi(k,j,i,iens), - uvel(k,j,i,iens), - wvel(k,j,i,iens), - debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), - debug_save_rhov(k,j,i,iens), - debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens), - debug_save_uvel(k,j,i,iens), - debug_save_wvel(k,j,i,iens) - ); - } - // Check for large vertical velocity - const auto is_large_pos_w = wvel(k,j,i,iens)> 40; - const auto is_large_neg_w = wvel(k,j,i,iens)<-40; - if ( is_large_pos_w || is_large_neg_w ) { - printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + // // Check for low temperature + // const auto is_low_t = temp(k,j,i,iens)<100; + // if ( is_low_t ) { + // printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + // nstep,id,k,i,iens,lat(iens),lon(iens),phis, + // temp(k,j,i,iens), + // rhod(k,j,i,iens), + // rhov(k,j,i,iens), + // rhoc(k,j,i,iens), + // rhoi(k,j,i,iens), + // uvel(k,j,i,iens), + // wvel(k,j,i,iens), + // debug_save_temp(k,j,i,iens), + // debug_save_rhod(k,j,i,iens), + // debug_save_rhov(k,j,i,iens), + // debug_save_rhoc(k,j,i,iens), + // debug_save_rhoi(k,j,i,iens), + // debug_save_uvel(k,j,i,iens), + // debug_save_wvel(k,j,i,iens) + // ); + // } + // Check for large temperature drops + const auto is_drop_t = (temp(k,j,i,iens)-debug_save_temp(k,j,i,iens))<-50; + if ( is_drop_t ) { + printf("PAM-DEBUG drop-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", nstep,id,k,i,iens,lat(iens),lon(iens),phis, temp(k,j,i,iens), rhod(k,j,i,iens), @@ -185,6 +184,28 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { debug_save_wvel(k,j,i,iens) ); } + // // Check for large vertical velocity + // const auto is_large_pos_w = wvel(k,j,i,iens)> 40; + // const auto is_large_neg_w = wvel(k,j,i,iens)<-40; + // if ( is_large_pos_w || is_large_neg_w ) { + // printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + // nstep,id,k,i,iens,lat(iens),lon(iens),phis, + // temp(k,j,i,iens), + // rhod(k,j,i,iens), + // rhov(k,j,i,iens), + // rhoc(k,j,i,iens), + // rhoi(k,j,i,iens), + // uvel(k,j,i,iens), + // wvel(k,j,i,iens), + // debug_save_temp(k,j,i,iens), + // debug_save_rhod(k,j,i,iens), + // debug_save_rhov(k,j,i,iens), + // debug_save_rhoc(k,j,i,iens), + // debug_save_rhoi(k,j,i,iens), + // debug_save_uvel(k,j,i,iens), + // debug_save_wvel(k,j,i,iens) + // ); + // } // update saved previous values debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); From 0720d0dca888c047638492a6c5312fb5932d88aa Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 9 Apr 2024 11:24:16 -0700 Subject: [PATCH 098/388] disable mean-state acceleration for dry density --- .../eam/src/physics/crm/pam/pam_accelerate.h | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_accelerate.h b/components/eam/src/physics/crm/pam/pam_accelerate.h index a48ca628f69..a7b179a85c9 100644 --- a/components/eam/src/physics/crm/pam/pam_accelerate.h +++ b/components/eam/src/physics/crm/pam/pam_accelerate.h @@ -25,7 +25,7 @@ inline void pam_accelerate_init( pam::PamCoupler &coupler ) { auto crm_accel_uv = coupler.get_option("crm_accel_uv"); //------------------------------------------------------------------------------------------------ dm_device.register_and_allocate("accel_save_t", "saved temperature for MSA", {nz,nens}, {"z","nens"} ); - dm_device.register_and_allocate("accel_save_r", "saved dry density for MSA", {nz,nens}, {"z","nens"} ); + // dm_device.register_and_allocate("accel_save_r", "saved dry density for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_q", "saved total water for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_u", "saved uvel for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_v", "saved vvel for MSA", {nz,nens}, {"z","nens"} ); @@ -45,14 +45,14 @@ inline void pam_accelerate_diagnose( pam::PamCoupler &coupler ) { auto crm_accel_uv = coupler.get_option("crm_accel_uv"); //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); - auto rhod = dm_device.get("density_dry"); + // auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhol = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice" ); auto uvel = dm_device.get("uvel" ); auto vvel = dm_device.get("vvel" ); auto accel_save_t = dm_device.get("accel_save_t"); - auto accel_save_r = dm_device.get("accel_save_r"); + // auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_q = dm_device.get("accel_save_q"); auto accel_save_u = dm_device.get("accel_save_u"); auto accel_save_v = dm_device.get("accel_save_v"); @@ -60,7 +60,7 @@ inline void pam_accelerate_diagnose( pam::PamCoupler &coupler ) { // compute horizontal means needed later for mean-state acceleration parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { accel_save_t(k,n) = 0.0; - accel_save_r(k,n) = 0.0; + // accel_save_r(k,n) = 0.0; accel_save_q(k,n) = 0.0; if (crm_accel_uv) { accel_save_u(k,n) = 0.0; @@ -70,7 +70,7 @@ inline void pam_accelerate_diagnose( pam::PamCoupler &coupler ) { real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { yakl::atomicAdd( accel_save_t(k,n), temp(k,j,i,n) * r_nx_ny ); - yakl::atomicAdd( accel_save_r(k,n), rhod(k,j,i,n) * r_nx_ny ); + // yakl::atomicAdd( accel_save_r(k,n), rhod(k,j,i,n) * r_nx_ny ); yakl::atomicAdd( accel_save_q(k,n), ( rhov(k,j,i,n) + rhol(k,j,i,n) + rhoi(k,j,i,n) ) * r_nx_ny ); if (crm_accel_uv) { yakl::atomicAdd( accel_save_u(k,n), uvel(k,j,i,n) * r_nx_ny ); @@ -93,14 +93,14 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { auto nx = coupler.get_option("crm_nx"); //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); - auto rhod = dm_device.get("density_dry"); + // auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhol = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice" ); auto uvel = dm_device.get("uvel" ); auto vvel = dm_device.get("vvel" ); auto accel_save_t = dm_device.get("accel_save_t"); - auto accel_save_r = dm_device.get("accel_save_r"); + // auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_q = dm_device.get("accel_save_q"); auto accel_save_u = dm_device.get("accel_save_u"); auto accel_save_v = dm_device.get("accel_save_v"); @@ -109,12 +109,12 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { real crm_accel_factor = coupler.get_option("crm_accel_factor"); //------------------------------------------------------------------------------------------------ real2d hmean_t ("hmean_t", nz,nens); - real2d hmean_r ("hmean_r", nz,nens); + // real2d hmean_r ("hmean_r", nz,nens); real2d hmean_q ("hmean_q", nz,nens); real2d hmean_u ("hmean_u", nz,nens); real2d hmean_v ("hmean_v", nz,nens); real2d ttend_acc("ttend_acc", nz,nens); - real2d rtend_acc("rtend_acc", nz,nens); + // real2d rtend_acc("rtend_acc", nz,nens); real2d qtend_acc("qtend_acc", nz,nens); real2d utend_acc("utend_acc", nz,nens); real2d vtend_acc("vtend_acc", nz,nens); @@ -127,7 +127,7 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { // Compute the horizontal mean for each variable parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { hmean_t(k,n) = 0.0; - hmean_r(k,n) = 0.0; + // hmean_r(k,n) = 0.0; hmean_q(k,n) = 0.0; if (crm_accel_uv) { hmean_u(k,n) = 0.0; @@ -137,7 +137,7 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { yakl::atomicAdd( hmean_t(k,n), temp(k,j,i,n) * r_nx_ny ); - yakl::atomicAdd( hmean_r(k,n), rhod(k,j,i,n) * r_nx_ny ); + // yakl::atomicAdd( hmean_r(k,n), rhod(k,j,i,n) * r_nx_ny ); yakl::atomicAdd( hmean_q(k,n), ( rhov(k,j,i,n) + rhol(k,j,i,n) + rhoi(k,j,i,n) ) * r_nx_ny ); if (crm_accel_uv) { yakl::atomicAdd( hmean_u(k,n), uvel(k,j,i,n) * r_nx_ny ); @@ -150,7 +150,7 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { ScalarLiveOut ceaseflag_liveout(false); parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { ttend_acc(k,n) = hmean_t(k,n) - accel_save_t(k,n); - rtend_acc(k,n) = hmean_r(k,n) - accel_save_r(k,n); + // rtend_acc(k,n) = hmean_r(k,n) - accel_save_r(k,n); qtend_acc(k,n) = hmean_q(k,n) - accel_save_q(k,n); if (crm_accel_uv) { utend_acc(k,n) = hmean_u(k,n) - accel_save_u(k,n); @@ -193,7 +193,7 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { temp(k,j,i,n) = temp(k,j,i,n) + crm_accel_factor * ttend_acc(k,n); - rhod(k,j,i,n) = rhod(k,j,i,n) + crm_accel_factor * rtend_acc(k,n); + // rhod(k,j,i,n) = rhod(k,j,i,n) + crm_accel_factor * rtend_acc(k,n); rhov(k,j,i,n) = rhov(k,j,i,n) + crm_accel_factor * qtend_acc(k,n); if (crm_accel_uv) { uvel(k,j,i,n) = uvel(k,j,i,n) + crm_accel_factor * utend_acc(k,n); From 081b18326623709d8f7019d4fcaedec551c51852 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 9 Apr 2024 11:29:11 -0700 Subject: [PATCH 099/388] update pam_driver --- components/eam/src/physics/crm/pam/pam_driver.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index e6f85ed0d5a..69e67a90894 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -25,7 +25,7 @@ #include "p3_f90.hpp" #include "pam_debug.h" -bool constexpr enable_check_state = false; +bool constexpr enable_check_state = true; extern "C" void pam_driver() { //------------------------------------------------------------------------------------------------ @@ -62,7 +62,7 @@ extern "C" void pam_driver() { coupler.set_option("spam_clip_vertical_velocities",true); coupler.set_option("spam_adjust_crm_per_phys_using_vert_cfl",true); coupler.set_option("spam_target_cfl",0.7); - coupler.set_option("spam_max_w",50.0); + coupler.set_option("spam_max_w",30.0); //------------------------------------------------------------------------------------------------ // Allocate the coupler state and retrieve host/device data managers coupler.allocate_coupler_state( crm_nz , crm_ny , crm_nx , nens ); @@ -91,8 +91,10 @@ extern "C" void pam_driver() { // Copy input CRM state (saved by the GCM) to coupler pam_state_copy_input_to_coupler(coupler); - // // update CRM dry density to match GCM and disable dry density forcing - // pam_state_update_dry_density(coupler); + #ifdef MMF_DISABLE_DENSITY_FORCING + // update CRM dry density to match GCM and disable dry density forcing + pam_state_update_dry_density(coupler); + #endif // if debugging - initialize saved state variables and check initial CRM state if (enable_check_state) { From 5e8b488dce3c4eab15346db343dcc8f92395c474 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Tue, 9 Apr 2024 14:18:12 -0700 Subject: [PATCH 100/388] Fix small bug in setting islandMask Fix small bug in setting islandMask. Also apply suggestions from code review. --- .../src/mode_forward/mpas_li_calving.F | 98 +++++++++++-------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 7d4b7799520..6997af42249 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -320,7 +320,7 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) - call remove_small_islands(meshPool, geometryPool, domain) + call remove_small_islands(domain, err_tmp) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) @@ -1032,16 +1032,14 @@ end subroutine floating_calving !> unrealistic velocities in the Albany velocity solver. Specifically, this !> finds one- and two-cell masses of grounded ice that are surrounded by dynamic !> floating ice ice shelves ≥1 cell wide. It eliminates the dynamic cells -!> (both grounded and floating) in these islands by sending them to the -!> and then cleans up stranded non-dynamic cells using a flood-fill routine. +!> (both grounded and floating) in these islands by sending them to the calving +!> flux and then cleans up stranded non-dynamic cells using a flood-fill routine. !----------------------------------------------------------------------- - subroutine remove_small_islands(meshPool, geometryPool, domain) - type (mpas_pool_type), pointer, intent(in) :: meshPool !< Input: Mesh pool - type (mpas_pool_type), pointer, intent(inout) :: geometryPool !< Input: Geometry pool + subroutine remove_small_islands(domain, err) type (domain_type), intent(inout) :: domain !< Input/Output: domain object - - type (mpas_pool_type), pointer :: scratchPool + integer, intent(inout) :: err + type (mpas_pool_type), pointer :: scratchPool, meshPool, geometryPool, velocityPool logical, pointer :: config_remove_small_islands real (kind=RKIND), dimension(:), pointer :: calvingThickness ! thickness of ice that calves (computed in this subroutine) real (kind=RKIND), dimension(:), pointer :: calvingThicknessFromThreshold ! thickness of ice that calves (computed in this subroutine) @@ -1053,6 +1051,7 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) integer, pointer :: nCells, maxEdges logical :: removeIsland integer :: iCell, jCell, kCell, m, n, count + integer :: nIslandCellsLocal, nIslandCellsGlobal integer :: nGroundedNeighbors, nGroundedNeighborsJCell integer, dimension(:), allocatable :: connectedCellsList integer, dimension(:), allocatable :: islandMask @@ -1066,6 +1065,9 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) endif call mpas_pool_get_subpool(domain % blocklist % structs, 'scratch', scratchPool) + call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(domain % blocklist % structs, 'geometry', geometryPool) + call mpas_pool_get_subpool(domain % blocklist % structs, 'velocity', velocityPool) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) call mpas_pool_get_dimension(meshPool, 'maxEdges', maxEdges) @@ -1080,7 +1082,8 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) islandMask(nCells+1)) islandMask(:) = 0 - + nIslandCellsLocal = 0 + nIslandCellsGlobal = 0 ! Allocate scratch fields for flood-fill call mpas_pool_get_field(scratchPool, 'seedMask', seedMaskField) call mpas_allocate_scratch_field(seedMaskField, single_block_in = .true.) @@ -1096,7 +1099,7 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) ! which are potentially islands that need to be removed. do iCell = 1, nCells if (li_mask_is_grounded_ice(cellMask(iCell))) then - + islandMask(iCell) = 1 ! Potentially an island. Further evaluated below. nGroundedNeighbors = 0 ! Count grounded neighbors do n = 1, nEdgesOnCell(iCell) @@ -1120,11 +1123,10 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) ! fewer other grounded cells, then it should potentially ! be removed. If its dynamic neighbors have other grounded ! neighbors, then it is not an island. - if ( (nGroundedNeighborsJCell .le. 1) .and. & - (nGroundedNeighbors .le. 1) ) then - islandMask(iCell) = 1 - else + if ( (nGroundedNeighborsJCell > 1) .or. & + (nGroundedNeighbors > 1) ) then islandMask(iCell) = 0 + exit endif enddo endif @@ -1166,53 +1168,63 @@ subroutine remove_small_islands(meshPool, geometryPool, domain) do n = 1, (maxEdges+1)**2 if (connectedCellsList(n) == -1) then exit ! We've reached the end of the list. - else - jCell = connectedCellsList(n) - do m = 1, nEdgesOnCell(jCell) - kCell = cellsOnCell(m, jCell) - if ( li_mask_is_dynamic_ice(cellMask(kCell)) .and. & - (.not. any(connectedCellsList == kCell)) ) then - removeIsland = .false. - exit - endif - enddo endif + jCell = connectedCellsList(n) + do m = 1, nEdgesOnCell(jCell) + kCell = cellsOnCell(m, jCell) + if ( li_mask_is_dynamic_ice(cellMask(kCell)) .and. & + (.not. any(connectedCellsList == kCell)) ) then + removeIsland = .false. + exit + endif + enddo enddo ! Actually remove island - ! TODO: halo update needed? Would need to change logic. if ( removeIsland ) then + nIslandCellsLocal = nIslandCellsLocal + count do n = 1, count calvingThickness(connectedCellsList(n)) = calvingThickness(connectedCellsList(n)) + & thickness(connectedCellsList(n)) calvingThicknessFromThreshold(connectedCellsList(n)) = & calvingThicknessFromThreshold(connectedCellsList(n)) + thickness(connectedCellsList(n)) thickness(connectedCellsList(n)) = 0.0_RKIND + ! No need to evaluate any cells in this list again. + if (islandMask(connectedCellsList(n)) == 1) islandMask(connectedCellsList(n)) = 0 enddo endif endif enddo - ! Clean up by removing non-dynamic ice that may have been left behind - ! after islands where removed. - where (li_mask_is_grounded_ice(cellMask)) - seedMask = 1 - end where + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'thickness') + call mpas_dmpar_field_halo_exch(domain, 'calvingThickness') + call mpas_timer_stop("halo updates") + call li_calculate_mask(meshPool, velocityPool, geometryPool, err) - where (li_mask_is_ice(cellMask)) - growMask = 1 - end where + call mpas_dmpar_sum_int(domain % dminfo, nIslandCellsLocal, nIslandCellsGlobal) - call mpas_log_write("***Cleaning up stranded cells after removing small islands***") - call li_flood_fill(seedMask, growMask, domain) - do iCell = 1, nCells - if (li_mask_is_floating_ice(cellMask(iCell)) .and. seedMask(iCell) == 0) then - calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell) - calvingThicknessFromThreshold(iCell) = calvingThicknessFromThreshold(iCell) + thickness(iCell) - thickness(iCell) = 0.0_RKIND - endif - enddo - call mpas_log_write("***Finished cleaning up after removing small islands***") + if ( nIslandCellsGlobal > 0 ) then + ! Clean up by removing non-dynamic ice that may have been left behind + ! after islands where removed. + where (li_mask_is_grounded_ice(cellMask)) + seedMask = 1 + end where + + where (li_mask_is_ice(cellMask)) + growMask = 1 + end where + call mpas_log_write("***Cleaning up stranded cells after removing small islands***") + call li_flood_fill(seedMask, growMask, domain) + do iCell = 1, nCells + if (li_mask_is_floating_ice(cellMask(iCell)) .and. seedMask(iCell) == 0) then + calvingThickness(iCell) = calvingThickness(iCell) + thickness(iCell) + calvingThicknessFromThreshold(iCell) = calvingThicknessFromThreshold(iCell) + thickness(iCell) + thickness(iCell) = 0.0_RKIND + endif + enddo + call mpas_log_write("***Finished cleaning up after removing small islands***") + endif deallocate(connectedCellsList, & islandMask) call mpas_deallocate_scratch_field(seedMaskField, single_block_in=.true.) From 338d3e693e8aeabbb0e6126941eb91ef8c4501a1 Mon Sep 17 00:00:00 2001 From: alexolinhager <131483939+alexolinhager@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:10:36 -0700 Subject: [PATCH 101/388] Apply suggestions from code review Co-authored-by: Matt Hoffman --- .../mpas-albany-landice/src/Registry_subglacial_hydro.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 61d8fa7f681..12c669d9093 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -231,12 +231,12 @@ + description="distributed discharge across the grounding line, summed from grounding line edges to adjacent ungrounded cell. Values from all edges are summed if multiple grounding line edges border a single ungrounded cell" /> + description="total (channel + dist.) discharge across the grounding line, summed from grounding line edges to adjacent ungrounded cell. Values from all edges are summed if multiple grounding line edges border a single ungrounded cell" /> + description="channel discharge across the grounding line, summed from grounding line edges to adjacent ungrounded cell. Values from all edges are summed if multiple grounding line edges border a single ungrounded cell" /> Date: Tue, 9 Apr 2024 18:15:49 -0600 Subject: [PATCH 102/388] Minor PR Review Edits Minor edits to code following PR review --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 009a4e4f2ec..0028e75086e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -562,10 +562,6 @@ subroutine li_SGH_solve(domain, err) block => block % next end do - call mpas_timer_start("halo updates") - call mpas_dmpar_field_halo_exch(domain, 'totalGroundingLineDischargeCell') - call mpas_dmpar_field_halo_exch(domain, 'totalGroundingLineDischargeEdge') - call mpas_timer_stop("halo updates") ! ============= ! Update water layer thickness @@ -2318,7 +2314,6 @@ subroutine calc_gl_totals(block, err) real (kind=RKIND), dimension(:), pointer :: distGroundingLineDischargeCell real (kind=RKIND), dimension(:), pointer :: chnlGroundingLineDischargeCell real (kind=RKIND), dimension(:), pointer :: totalGroundingLineDischargeCell - real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: channelDischarge real (kind=RKIND), dimension(:), pointer :: waterFlux real (kind=RKIND), dimension(:), pointer :: dvEdge @@ -2330,7 +2325,6 @@ subroutine calc_gl_totals(block, err) real (kind=RKIND) :: distGroundingLineDischargeEdge real (kind=RKIND) :: chnlGroundingLineDischargeEdge real (kind=RKIND) :: totalGroundingLineDischargeEdge - real (kind=RKIND), pointer :: config_sea_level call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) @@ -2339,7 +2333,6 @@ subroutine calc_gl_totals(block, err) call mpas_pool_get_array(hydroPool, 'distGroundingLineDischargeCell', distGroundingLineDischargeCell) call mpas_pool_get_array(hydroPool, 'chnlGroundingLineDischargeCell', chnlGroundingLineDischargeCell) call mpas_pool_get_array(hydroPool, 'totalGroundingLineDischargeCell', totalGroundingLineDischargeCell) - call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'channelDischarge', channelDischarge) call mpas_pool_get_array(hydroPool, 'waterFlux', waterFlux) call mpas_pool_get_array(meshPool, 'dvEdge', dvEdge) @@ -2347,18 +2340,18 @@ subroutine calc_gl_totals(block, err) call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) - call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) distGroundingLineDischargeCell(:) = 0.0_RKIND chnlGroundingLineDischargeCell(:) = 0.0_RKIND totalGroundingLineDischargeCell(:) = 0.0_RKIND do iEdge = 1, nEdgesSolve - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) if (hydroMarineMarginMask(iEdge) == 1) then + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + !calculate totals at each grounding line edge distGroundingLineDischargeEdge = abs(waterFlux(iEdge) * dvEdge(iEdge)) chnlGroundingLineDischargeEdge = abs(channelDischarge(iEdge)) From 40c5a75790c972a0458ad73a2eabb4f14a7b03c5 Mon Sep 17 00:00:00 2001 From: Matt Hoffman Date: Tue, 9 Apr 2024 20:20:06 -0600 Subject: [PATCH 103/388] Remove whitespace addition --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 1 - 1 file changed, 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 0028e75086e..d54d87356c8 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1802,7 +1802,6 @@ subroutine update_channel(block, err) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(hydroPool, 'channelDiffusivity', channelDiffusivity) call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - ! Calculate terms needed for opening (melt) rate where(gradMagPhiEdge < 0.01_RKIND) channelDischarge(:) = 0.0_RKIND From c7cbee480925f25e5a4945f2993eeaba806e99b6 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Apr 2024 12:19:23 -0600 Subject: [PATCH 104/388] Apply suggestions from code review Add more descriptive comments. Co-authored-by: Matt Hoffman --- .../src/mode_forward/mpas_li_calving.F | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 6997af42249..5de1d6f5c7e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -1095,8 +1095,12 @@ subroutine remove_small_islands(domain, err) growMask => growMaskField % array growMask(:) = 0 - ! Loop over cells to find one- and two-cell regions of grounded ice, - ! which are potentially islands that need to be removed. + ! Loop over cells to find one- and two-cell regions of grounded ice + ! that are not dynamically connected to other grounded regions, + ! which are "islands" that potentially need to be removed. + ! In this first phase we identify islands that meet these + ! criteria. In phase 2 below we check if islands are dynamically + ! connected to floating ice, which will disqualify them for removal. do iCell = 1, nCells if (li_mask_is_grounded_ice(cellMask(iCell))) then islandMask(iCell) = 1 ! Potentially an island. Further evaluated below. @@ -1132,12 +1136,14 @@ subroutine remove_small_islands(domain, err) endif enddo - ! Determine whether to remove each island. First, make a list of the - ! dynamic neighbors of the cells in islandMask. If the grounded island - ! cell has a grounded neighbour, add that neighbor's dynamic neighbors + ! Determine whether to remove each island based on if it is dynamically + ! connected to other regions. For each cell in islandMask, + ! first make a list of its dynamic neighbors. If the grounded island + ! cell has a grounded neighbor, add that neighbor's dynamic neighbors ! to the list. Then, check that all the dynamic neighbors of the cells ! in the list are also in the list. If so, then this is considered an - ! island and is removed. If not, then leave it alone. + ! isolated island and is removed. If not, then it is dynamically connected + ! to other regions, so we leave it alone. do iCell = 1, nCells connectedCellsList(:) = -1 if (islandMask(iCell) == 1) then @@ -1182,6 +1188,10 @@ subroutine remove_small_islands(domain, err) ! Actually remove island if ( removeIsland ) then nIslandCellsLocal = nIslandCellsLocal + count + ! Note: nIslandCellsLocal may be inaccurate as neighbors or neighbors of neighbors to iCell + ! may get tallied multiple times from different members of islandMask. However, we only need + ! to know if nIslandCells>0, so this is ok. If we ever need an accurate value of nIslandCells, + ! some additional steps must be taken to avoid potential double counting. do n = 1, count calvingThickness(connectedCellsList(n)) = calvingThickness(connectedCellsList(n)) + & thickness(connectedCellsList(n)) From 0f9b78db2f4f77db99a0d43b889f65408bbb3394 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Apr 2024 12:26:06 -0600 Subject: [PATCH 105/388] Apply more suggestions from code review Add another verbose comment. Co-authored-by: Matt Hoffman --- .../src/mode_forward/mpas_li_calving.F | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 5de1d6f5c7e..054bc897574 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -1123,10 +1123,15 @@ subroutine remove_small_islands(domain, err) endif enddo endif - ! If this grounded cell is dynamically connected to 1 or - ! fewer other grounded cells, then it should potentially - ! be removed. If its dynamic neighbors have other grounded - ! neighbors, then it is not an island. + ! Two checks that a grounded cell is NOT a 1 or 2 cell island: + ! 1. If a grounded cell has more than 1 grounded neighbor, it is not an island + ! This is the nGroundedNeighbors criterion. It gets re-evaluated with every + ! neighbor each time through the loop. It may not trigger on early checks + ! but it will trigger eventually if this cell has more than 1 grounded neighbor. + ! 2. If its dynamic neighbors have other grounded neighbors, then we do not + ! consider it an island. This is the nGroundedNeighborsJCell criterion. + ! Any grounded cells that survive these two checks are considered islands + ! and are further evaluated in the next phase. if ( (nGroundedNeighborsJCell > 1) .or. & (nGroundedNeighbors > 1) ) then islandMask(iCell) = 0 From e30be2d77f627c8fed81ffadf35a927cd430a5b2 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Wed, 10 Apr 2024 12:27:48 -0700 Subject: [PATCH 106/388] Add some further clarifying comments Add some further clarifying comments, and label phases 1 and 2. --- .../src/mode_forward/mpas_li_calving.F | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index 054bc897574..de2a523e933 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -1095,12 +1095,14 @@ subroutine remove_small_islands(domain, err) growMask => growMaskField % array growMask(:) = 0 - ! Loop over cells to find one- and two-cell regions of grounded ice - ! that are not dynamically connected to other grounded regions, - ! which are "islands" that potentially need to be removed. + ! Phase 1: Loop over cells to find one- and two-cell regions of + ! grounded ice that are not dynamically connected to other grounded + ! regions, which are "islands" that potentially need to be removed. ! In this first phase we identify islands that meet these - ! criteria. In phase 2 below we check if islands are dynamically - ! connected to floating ice, which will disqualify them for removal. + ! criteria. In phase 2 below we check if islands are dynamically + ! connected to more extensive floating ice, which will disqualify + ! them for removal to avoid removing pinning points from ice + ! shelves, for example. do iCell = 1, nCells if (li_mask_is_grounded_ice(cellMask(iCell))) then islandMask(iCell) = 1 ! Potentially an island. Further evaluated below. @@ -1141,8 +1143,8 @@ subroutine remove_small_islands(domain, err) endif enddo - ! Determine whether to remove each island based on if it is dynamically - ! connected to other regions. For each cell in islandMask, + ! Phase 2: Determine whether to remove each island based on if it is + ! dynamically connected to other regions. For each cell in islandMask, ! first make a list of its dynamic neighbors. If the grounded island ! cell has a grounded neighbor, add that neighbor's dynamic neighbors ! to the list. Then, check that all the dynamic neighbors of the cells From fcb801bf90e7bd379b510e2c2ff3ee75e5992186 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:06:32 -0400 Subject: [PATCH 107/388] adjust white space --- components/eam/src/physics/crm/crm_physics.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/src/physics/crm/crm_physics.F90 b/components/eam/src/physics/crm/crm_physics.F90 index 2beeded06bb..51628d5ea74 100644 --- a/components/eam/src/physics/crm/crm_physics.F90 +++ b/components/eam/src/physics/crm/crm_physics.F90 @@ -1384,8 +1384,8 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, call pam_mirror_array_readwrite( 'output_ni_mean', crm_output%ni_mean, '' ) call pam_mirror_array_readwrite( 'output_qm_mean', crm_output%qm_mean, '' ) call pam_mirror_array_readwrite( 'output_bm_mean', crm_output%bm_mean, '' ) - call pam_mirror_array_readwrite( 'output_rho_d_mean', crm_output%rho_d_mean, '' ) - call pam_mirror_array_readwrite( 'output_rho_v_mean', crm_output%rho_v_mean, '' ) + call pam_mirror_array_readwrite( 'output_rho_d_mean', crm_output%rho_d_mean, '' ) + call pam_mirror_array_readwrite( 'output_rho_v_mean', crm_output%rho_v_mean, '' ) call pam_mirror_array_readwrite( 'output_qt_ls', crm_output%qt_ls, '' ) call pam_mirror_array_readwrite( 'output_t_ls', crm_output%t_ls, '' ) From 44ba5145df639f554be9e931740848f39a63464f Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:13:13 -0400 Subject: [PATCH 108/388] change how PAM reference state pressure is set --- .../eam/src/physics/crm/pam/pam_state.h | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index a34a867eb6e..fb6553df07e 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -108,6 +108,7 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { auto &dm_device = coupler.get_data_manager_device_readwrite(); auto nens = coupler.get_option("ncrms"); auto nz = coupler.get_option("crm_nz"); + auto gcm_nlev = coupler.get_option("gcm_nlev"); auto ref_presi = dm_device.get("ref_presi"); auto ref_pres = dm_device.get("ref_pres"); auto ref_rho_d = dm_device.get("ref_density_dry"); @@ -131,6 +132,14 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { auto rho_v = dm_device.get("water_vapor"); auto rho_c = dm_device.get("cloud_water"); auto rho_i = dm_device.get("ice"); + + auto &dm_host = coupler.get_data_manager_host_readonly(); + auto input_pmid = dm_host.get("input_pmid").createDeviceCopy(); + auto input_pint = dm_host.get("input_pint").createDeviceCopy(); + + auto lat = dm_host.get("latitude" ).createDeviceCopy(); + auto lon = dm_host.get("longitude" ).createDeviceCopy(); + auto input_phis = dm_host.get("input_phis").createDeviceCopy(); //------------------------------------------------------------------------------------------------ // Set anelastic reference state with current CRM mean state @@ -157,48 +166,34 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { }); // calculate horizontal means parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { - real pmid_tmp = rho_d(k,j,i,iens)*R_d*temp(k,j,i,iens) + rho_v(k,j,i,iens)*R_v*temp(k,j,i,iens); - atomicAdd( hmean_pmid (k,iens), pmid_tmp * r_nx_ny ); atomicAdd( hmean_rho_d(k,iens), rho_d (k,j,i,iens) * r_nx_ny ); atomicAdd( hmean_rho_v(k,iens), rho_v (k,j,i,iens) * r_nx_ny ); atomicAdd( hmean_rho_c(k,iens), rho_c (k,j,i,iens) * r_nx_ny ); atomicAdd( hmean_rho_i(k,iens), rho_i (k,j,i,iens) * r_nx_ny ); atomicAdd( hmean_temp (k,iens), temp (k,j,i,iens) * r_nx_ny ); }); - // calculate interface pressure from mid-level pressure - // parallel_for(SimpleBounds<4>(nz+1,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int iens) { - parallel_for(SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k, int iens) { - if (k == 0 ) { - real rho = hmean_rho_d(k,iens)+hmean_rho_v(k,iens); - real dz = zint(k+1,iens)-zint(k,iens); - hmean_pint(k,iens) = hmean_pmid(k ,iens) + grav*rho*dz/2; - } else if (k == nz) { - real rho = hmean_rho_d(k-1,iens)+hmean_rho_v(k-1,iens); - real dz = zint(k,iens)-zint(k-1,iens); - hmean_pint(k,iens) = hmean_pmid(k-1,iens) - grav*rho*dz/2; - } else { - real rhokm1 = hmean_rho_d(k-1,iens)+hmean_rho_v(k-1,iens);; - real rhokm0 = hmean_rho_d(k ,iens)+hmean_rho_v(k ,iens); - real dzkm1 = zint(k ,iens)-zint(k-1,iens); - real dzkm0 = zint(k+1,iens)-zint(k ,iens); - hmean_pint(k,iens) = 0.5_fp * ( hmean_pmid(k-1,iens) - grav*rhokm1*dzkm1/2 + - hmean_pmid(k ,iens) + grav*rhokm0*dzkm0/2 ); - } + + // Use GCM state for reference pressure - previously, the current CRM pressure + // was used, but the way the interface pressure was calculated led to problems + // in edge cases (ex. over topography) - switching to GCM pressure works well + parallel_for( SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k_crm, int iens) { + int k_gcm = (gcm_nlev+1)-1-k_crm; + hmean_pint(k_crm,iens) = input_pint(k_gcm,iens); + }); + parallel_for(SimpleBounds<2>(nz,nens), YAKL_LAMBDA (int k_crm, int iens) { + int k_gcm = gcm_nlev-1-k_crm; + hmean_pmid(k_crm,iens) = input_pmid(k_gcm,iens); }); - auto &dm_host = coupler.get_data_manager_host_readonly(); - auto lat = dm_host.get("latitude" ).createDeviceCopy(); - auto lon = dm_host.get("longitude" ).createDeviceCopy(); - auto input_phis = dm_host.get("input_phis").createDeviceCopy(); // check that interface pressure is reasonable - parallel_for(SimpleBounds<2>(nz+1,nens) , YAKL_LAMBDA (int k, int iens) { + parallel_for(SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int iens) { if ( hmean_pint(k,iens) < hmean_pmid(k,iens) ) { auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG bad-pint - k:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- pint:%8.2g pmid:%8.2g \n", - k,iens,lat(iens),lon(iens),phis, - hmean_pint(k,iens), - hmean_pmid(k,iens) - ); + printf("PAM-STATE - bad interface pressure for reference state - "+\ + "k:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- "+\ + "pint:%12.4f pmid:%12.4f \n", + k,iens,lat(iens),lon(iens),phis, + hmean_pint(k,iens),hmean_pmid(k,iens)); } }); From 8c8cb1c9e358119154f9ee4f974fc2d219a15c3b Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:14:45 -0400 Subject: [PATCH 109/388] update PAM variance transport --- .../physics/crm/pam/pam_variance_transport.h | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_variance_transport.h b/components/eam/src/physics/crm/pam/pam_variance_transport.h index 1033df4280d..ae9f0747ee3 100644 --- a/components/eam/src/physics/crm/pam/pam_variance_transport.h +++ b/components/eam/src/physics/crm/pam/pam_variance_transport.h @@ -38,6 +38,8 @@ inline void pam_variance_transport_diagnose( pam::PamCoupler &coupler ) { //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); auto rhov = dm_device.get("water_vapor"); + auto rhoc = dm_device.get("cloud_water"); + auto rhoi = dm_device.get("ice" ); auto uvel = dm_device.get("uvel" ); auto vt_temp = dm_device.get("vt_temp" ); auto vt_rhov = dm_device.get("vt_rhov" ); @@ -64,15 +66,17 @@ inline void pam_variance_transport_diagnose( pam::PamCoupler &coupler ) { // calculate horizontal mean real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int n) { + real rhot = rhov(k,j,i,n) + rhoc(k,j,i,n) + rhoi(k,j,i,n); yakl::atomicAdd( temp_mean(k,n), temp(k,j,i,n)*r_nx_ny ); - yakl::atomicAdd( rhov_mean(k,n), rhov(k,j,i,n)*r_nx_ny ); + yakl::atomicAdd( rhov_mean(k,n), rhot *r_nx_ny ); yakl::atomicAdd( uvel_mean(k,n), uvel(k,j,i,n)*r_nx_ny ); }); //------------------------------------------------------------------------------------------------ // calculate fluctuations from horz mean parallel_for(SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int n) { + real rhot = rhov(k,j,i,n) + rhoc(k,j,i,n) + rhoi(k,j,i,n); vt_temp_pert(k,j,i,n) = temp(k,j,i,n) - temp_mean(k,n); - vt_rhov_pert(k,j,i,n) = rhov(k,j,i,n) - rhov_mean(k,n); + vt_rhov_pert(k,j,i,n) = rhot - rhov_mean(k,n); vt_uvel_pert(k,j,i,n) = uvel(k,j,i,n) - uvel_mean(k,n); }); //------------------------------------------------------------------------------------------------ @@ -101,9 +105,6 @@ inline void pam_variance_transport_compute_forcing( pam::PamCoupler &coupler ) { // update CRM variance values pam_variance_transport_diagnose(coupler); //------------------------------------------------------------------------------------------------ - auto temp = dm_device.get("temp" ); - auto rhov = dm_device.get("water_vapor" ); - auto uvel = dm_device.get("uvel" ); auto vt_temp = dm_device.get("vt_temp" ); auto vt_rhov = dm_device.get("vt_rhov" ); auto vt_uvel = dm_device.get("vt_uvel" ); @@ -134,14 +135,16 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { auto nx = coupler.get_option("crm_nx"); auto crm_dt = coupler.get_option("crm_dt"); //------------------------------------------------------------------------------------------------ + // update CRM variance values + pam_variance_transport_diagnose(coupler); + //------------------------------------------------------------------------------------------------ // min and max perturbation scaling values are used to limit the // large-scale forcing from variance transport. This is meant to // protect against creating unstable situations, although // problematic scenarios were extremely rare in testing. - // A scaling limit of +/- 10% was found to be adequate in SAM, - // but PAM seems much more sensitive (not sure why), so we use 0.1% here - real constexpr pert_scale_min = 1.0 - 0.001; - real constexpr pert_scale_max = 1.0 + 0.001; + // A scaling limit of +/- 10% was found to be adequate. + real constexpr pert_scale_min = 1.0 - 0.1; + real constexpr pert_scale_max = 1.0 + 0.1; //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); auto rhov = dm_device.get("water_vapor" ); @@ -161,9 +164,6 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { real2d rhov_pert_scale("rhov_pert_scale", nz, nens); real2d uvel_pert_scale("uvel_pert_scale", nz, nens); //------------------------------------------------------------------------------------------------ - // update CRM variance values - pam_variance_transport_diagnose(coupler); - //------------------------------------------------------------------------------------------------ // calculate scaling factor for local perturbations parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { real tmp; @@ -172,9 +172,15 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { rhov_pert_scale(k,n) = 1.0; uvel_pert_scale(k,n) = 1.0; // calculate variance scaling factor - tmp = 1.+crm_dt*vt_temp_forcing_tend(k,n)/vt_temp(k,n); if (tmp>0){ temp_pert_scale(k,n) = sqrt(tmp); } - tmp = 1.+crm_dt*vt_rhov_forcing_tend(k,n)/vt_rhov(k,n); if (tmp>0){ rhov_pert_scale(k,n) = sqrt(tmp); } - tmp = 1.+crm_dt*vt_uvel_forcing_tend(k,n)/vt_uvel(k,n); if (tmp>0){ uvel_pert_scale(k,n) = sqrt(tmp); } + real tmp_t_scale = -1.0; + real tmp_q_scale = -1.0; + real tmp_u_scale = -1.0; + if (vt_temp(k,n)>0.0) { tmp_t_scale = 1. + crm_dt*vt_temp_forcing_tend(k,n) / vt_temp(k,n); } + if (vt_rhov(k,n)>0.0) { tmp_q_scale = 1. + crm_dt*vt_rhov_forcing_tend(k,n) / vt_rhov(k,n); } + if (vt_uvel(k,n)>0.0) { tmp_u_scale = 1. + crm_dt*vt_uvel_forcing_tend(k,n) / vt_uvel(k,n); } + if (tmp>0.0){ temp_pert_scale(k,n) = sqrt(tmp_t_scale); } + if (tmp>0.0){ rhov_pert_scale(k,n) = sqrt(tmp_q_scale); } + if (tmp>0.0){ uvel_pert_scale(k,n) = sqrt(tmp_u_scale); } // enforce minimum scaling temp_pert_scale(k,n) = std::max( temp_pert_scale(k,n), pert_scale_min ); rhov_pert_scale(k,n) = std::max( rhov_pert_scale(k,n), pert_scale_min ); @@ -213,9 +219,6 @@ inline void pam_variance_transport_compute_feedback( pam::PamCoupler &coupler ) // update CRM variance values pam_variance_transport_diagnose(coupler); //------------------------------------------------------------------------------------------------ - auto temp = dm_device.get("temp" ); - auto rhov = dm_device.get("water_vapor"); - auto uvel = dm_device.get("uvel" ); auto vt_temp = dm_device.get("vt_temp" ); auto vt_rhov = dm_device.get("vt_rhov" ); auto vt_uvel = dm_device.get("vt_uvel" ); From 98726502a74a6067dd2f4e96c04db227e5f3a790 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:16:11 -0400 Subject: [PATCH 110/388] update MMF2 default config --- components/eam/cime_config/config_component.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/eam/cime_config/config_component.xml b/components/eam/cime_config/config_component.xml index 784fe44195e..056b607953f 100755 --- a/components/eam/cime_config/config_component.xml +++ b/components/eam/cime_config/config_component.xml @@ -72,15 +72,15 @@ -crm samxx -crm_dt 10 - -crm pam -pam_dycor spam -crm_dt 5 - -crm pam -pam_dycor awfl -crm_dt 5 + -crm pam -pam_dycor spam -crm_dt 10 + -crm pam -pam_dycor awfl -crm_dt 10 -use_MMF -nlev 60 -crm_nz 50 -crm_dx 2000 -crm_nx 64 -crm_ny 1 -crm_nx_rad 4 -crm_ny_rad 1 -crm_dx 2000 -crm_nx 45 -crm_ny 1 -crm_nx_rad 5 -crm_ny_rad 1 -MMF_microphysics_scheme sam1mom -chem none -MMF_microphysics_scheme p3 -chem none -rad rrtmgp -rrtmgpxx - -use_MMF_VT + -use_MMF_VT -use_MMF_ESMT -aquaplanet -aquaplanet -rce From 2380d339ca04b8f6c878d2fcfdf76ecaa408663f Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:29:53 -0400 Subject: [PATCH 111/388] bug fix in PAM variance transport --- .../eam/src/physics/crm/pam/pam_variance_transport.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_variance_transport.h b/components/eam/src/physics/crm/pam/pam_variance_transport.h index ae9f0747ee3..e258b3b7f3a 100644 --- a/components/eam/src/physics/crm/pam/pam_variance_transport.h +++ b/components/eam/src/physics/crm/pam/pam_variance_transport.h @@ -143,8 +143,8 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { // protect against creating unstable situations, although // problematic scenarios were extremely rare in testing. // A scaling limit of +/- 10% was found to be adequate. - real constexpr pert_scale_min = 1.0 - 0.1; - real constexpr pert_scale_max = 1.0 + 0.1; + real constexpr pert_scale_min = 1.0 - 0.05; + real constexpr pert_scale_max = 1.0 + 0.05; //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); auto rhov = dm_device.get("water_vapor" ); @@ -166,7 +166,6 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { //------------------------------------------------------------------------------------------------ // calculate scaling factor for local perturbations parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { - real tmp; // initialize scaling factors to 1.0 temp_pert_scale(k,n) = 1.0; rhov_pert_scale(k,n) = 1.0; @@ -178,9 +177,9 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { if (vt_temp(k,n)>0.0) { tmp_t_scale = 1. + crm_dt*vt_temp_forcing_tend(k,n) / vt_temp(k,n); } if (vt_rhov(k,n)>0.0) { tmp_q_scale = 1. + crm_dt*vt_rhov_forcing_tend(k,n) / vt_rhov(k,n); } if (vt_uvel(k,n)>0.0) { tmp_u_scale = 1. + crm_dt*vt_uvel_forcing_tend(k,n) / vt_uvel(k,n); } - if (tmp>0.0){ temp_pert_scale(k,n) = sqrt(tmp_t_scale); } - if (tmp>0.0){ rhov_pert_scale(k,n) = sqrt(tmp_q_scale); } - if (tmp>0.0){ uvel_pert_scale(k,n) = sqrt(tmp_u_scale); } + if (tmp_t_scale>0.0){ temp_pert_scale(k,n) = sqrt(tmp_t_scale); } + if (tmp_q_scale>0.0){ rhov_pert_scale(k,n) = sqrt(tmp_q_scale); } + if (tmp_u_scale>0.0){ uvel_pert_scale(k,n) = sqrt(tmp_u_scale); } // enforce minimum scaling temp_pert_scale(k,n) = std::max( temp_pert_scale(k,n), pert_scale_min ); rhov_pert_scale(k,n) = std::max( rhov_pert_scale(k,n), pert_scale_min ); From 63df74c0bb17552d825f55cb3b04edc5f5b83014 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 12:30:50 -0400 Subject: [PATCH 112/388] implement PAM driver subcycling --- .../eam/src/physics/crm/pam/pam_driver.cpp | 173 ++++++++++++------ 1 file changed, 122 insertions(+), 51 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index 69e67a90894..0833d2beff8 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -1,5 +1,4 @@ #include "pam_coupler.h" -// #include "params.h" #include "Dycore.h" #include "Microphysics.h" #include "SGS.h" @@ -14,26 +13,90 @@ #include "pam_output.h" #include "pam_accelerate.h" #include "pam_variance_transport.h" +#include "pam_hyperdiffusion.h" #include "sponge_layer.h" #include "surface_friction.h" #include "scream_cxx_interface_finalize.h" -#include "pam_hyperdiffusion.h" - // Needed for p3_init #include "p3_functions.hpp" #include "p3_f90.hpp" #include "pam_debug.h" -bool constexpr enable_check_state = true; +bool constexpr enable_check_state = false; -extern "C" void pam_driver() { + +inline int pam_driver_set_subcycle_timestep( pam::PamCoupler &coupler, real crm_dt_fixed ) { + // calculate the CFL condition and adjust the PAM time loop subcylcing //------------------------------------------------------------------------------------------------ - using yakl::intrinsics::abs; - using yakl::intrinsics::maxval; - using yakl::atomicAdd; using yakl::c::parallel_for; using yakl::c::SimpleBounds; + using yakl::atomicMax; + //------------------------------------------------------------------------------------------------ + auto nens = coupler.get_option("ncrms"); + auto gcm_nlev = coupler.get_option("gcm_nlev"); + auto crm_nz = coupler.get_option("crm_nz"); + auto crm_nx = coupler.get_option("crm_nx"); + auto crm_ny = coupler.get_option("crm_ny"); + auto crm_dx = coupler.get_option("crm_dx"); + auto crm_dy = coupler.get_option("crm_dy"); + auto &dm_device = coupler.get_data_manager_device_readonly(); + auto &dm_host = coupler.get_data_manager_host_readonly(); + auto uvel = dm_device.get("uvel"); + auto wvel = dm_device.get("wvel"); + auto input_zint = dm_host.get("input_zint").createDeviceCopy(); + //------------------------------------------------------------------------------------------------ + yakl::ParallelMax pmax( crm_nz*nens ); + real cfl = 0; + int num_subcycle = 1; + int constexpr max_num_subcycle = 10; + real2d wvel_max("wvel_max",crm_nz,nens); + real2d uvel_max("uvel_max",crm_nz,nens); + real2d cfl_max("cfl_max", crm_nz,nens); + //------------------------------------------------------------------------------------------------ + // initialize max U and W arrays + parallel_for( SimpleBounds<2>(crm_nz,nens) , YAKL_LAMBDA (int k, int n) { + wvel_max(k,n) = 0.0; + uvel_max(k,n) = 0.0; + }); + // calculate max U and W + parallel_for( SimpleBounds<4>(crm_nz,crm_ny,crm_nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { + yakl::atomicMax(uvel_max(k,n), sqrt(uvel(k,j,i,n)*uvel(k,j,i,n)) ); + yakl::atomicMax(wvel_max(k,n), fabs(wvel(k,j,i,n)) ); + }); + // find max CFL between horizontal and vertical CFL values + parallel_for( SimpleBounds<2>(crm_nz,nens) , YAKL_LAMBDA (int k, int n) { + int k_gcm = gcm_nlev-1-k; + real crm_dz = input_zint(k_gcm,n) - input_zint(k_gcm+1,n); + real cfl_u = uvel_max(k,n)*crm_dt_fixed/crm_dx; + real cfl_w = wvel_max(k,n)*crm_dt_fixed/crm_dz; + cfl_max(k,n) = max(cfl_u,cfl_w); + }); + // calculate final CFL across ensemble + real cfl_loc = pmax(cfl_max.data()); + cfl = max(cfl,cfl_loc); + // update number of subcycles and time step + num_subcycle = max(num_subcycle,max(1,static_cast(ceil(cfl/0.7)))); + real crm_dt_subcycle = crm_dt_fixed / num_subcycle; + coupler.set_option("crm_dt",crm_dt_subcycle); + // check for excessive subcylcing - don't exit, just print + if(num_subcycle > max_num_subcycle) { + real umax = pmax(uvel_max.data()); + real wmax = pmax(wvel_max.data()); + printf("PAM_DRIVER - WARNING: excessive subcycling!"+\ + " - num_subcycle: %3.3d dt: %8.4f cfl: %8.4f umax: %8.2f wmax: %8.2f \n", + num_subcycle,crm_dt_subcycle,cfl,umax,wmax); + // exit(-1); + } + + return num_subcycle; + //------------------------------------------------------------------------------------------------ +} + + +extern "C" void pam_driver() { + // This is the primary method for running the PAM CRM in E3SM-MMF. + //------------------------------------------------------------------------------------------------ auto &coupler = pam_interface::get_coupler(); //------------------------------------------------------------------------------------------------ // retreive coupler options @@ -42,8 +105,10 @@ extern "C" void pam_driver() { auto crm_nz = coupler.get_option("crm_nz"); auto crm_nx = coupler.get_option("crm_nx"); auto crm_ny = coupler.get_option("crm_ny"); + // auto crm_dx = coupler.get_option("crm_dx"); + // auto crm_dy = coupler.get_option("crm_dy"); auto gcm_dt = coupler.get_option("gcm_dt"); - auto crm_dt = coupler.get_option("crm_dt"); + auto crm_dt_fixed = coupler.get_option("crm_dt"); auto is_first_step = coupler.get_option("is_first_step"); auto is_restart = coupler.get_option("is_restart"); bool use_crm_accel = coupler.get_option("use_crm_accel"); @@ -162,7 +227,7 @@ extern "C" void pam_driver() { //------------------------------------------------------------------------------------------------ // set number of CRM steps - int nstop = int(gcm_dt/crm_dt); + int nstop = int(gcm_dt/crm_dt_fixed); // for mean-state acceleration adjust nstop and diagnose horizontal means if (use_crm_accel) { @@ -171,51 +236,58 @@ extern "C" void pam_driver() { }; // Run the CRM - real etime_crm = 0; int nstep = 0; - // while (etime_crm < gcm_dt) { while (nstep < nstop) { - if (crm_dt == 0.) { crm_dt = dycore.compute_time_step(coupler); } - if (etime_crm + crm_dt > gcm_dt) { crm_dt = gcm_dt - etime_crm; } + //-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + auto num_subcycle = pam_driver_set_subcycle_timestep(coupler,crm_dt_fixed); + #if defined(MMF_PAM_DYCOR_SPAM) + dycore.update_dt(coupler); + #endif if (enable_check_state) { pam_debug_check_state(coupler, 1, nstep); } - // Apply forcing tendencies - if (use_MMF_VT) { pam_variance_transport_apply_forcing(coupler); } - if (enable_check_state) { pam_debug_check_state(coupler, 2, nstep); } - coupler.run_module( "apply_gcm_forcing_tendencies" , modules::apply_gcm_forcing_tendencies ); - if (enable_check_state) { pam_debug_check_state(coupler, 3, nstep); } - coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); - if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } - - // Dynamics - if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } - if (do_density_save_recall) { pam_state_save_dry_density(coupler); } - coupler.run_module( "dycore", [&] (pam::PamCoupler &coupler) {dycore.timeStep(coupler);} ); - if (do_density_save_recall) { pam_state_recall_dry_density(coupler); } - if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"dycor"); } - if (enable_check_state) { pam_debug_check_state(coupler, 5, nstep); } - - // Sponge layer damping - if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } - coupler.run_module( "sponge_layer", modules::sponge_layer ); - if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sponge"); } - - // Apply hyperdiffusion to account for lack of horizontal mixing in SHOC - pam_hyperdiffusion(coupler); - - // Turbulence - SHOC - coupler.run_module( "compute_surface_friction", modules::compute_surface_friction ); - if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } - coupler.run_module( "sgs", [&] (pam::PamCoupler &coupler) {sgs .timeStep(coupler);} ); - if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sgs"); } - if (enable_check_state) { pam_debug_check_state(coupler, 6, nstep); } - - // Microphysics - P3 - if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } - coupler.run_module( "micro", [&] (pam::PamCoupler &coupler) {micro .timeStep(coupler);} ); - if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"micro"); } - if (enable_check_state) { pam_debug_check_state(coupler, 7, nstep); } + // loop for adaptive subcyling based on CFL + for(int icycle=1; icycle<=num_subcycle; icycle++) { + + // Apply forcing tendencies + if (use_MMF_VT) { pam_variance_transport_apply_forcing(coupler); } + if (enable_check_state) { pam_debug_check_state(coupler, 2, nstep); } + coupler.run_module( "apply_gcm_forcing_tendencies" , modules::apply_gcm_forcing_tendencies ); + if (enable_check_state) { pam_debug_check_state(coupler, 3, nstep); } + coupler.run_module( "radiation" , [&] (pam::PamCoupler &coupler) {rad .timeStep(coupler);} ); + if (enable_check_state) { pam_debug_check_state(coupler, 4, nstep); } + + // Dynamics + if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } + if (do_density_save_recall) { pam_state_save_dry_density(coupler); } + coupler.run_module( "dycore", [&] (pam::PamCoupler &coupler) {dycore.timeStep(coupler);} ); + if (do_density_save_recall) { pam_state_recall_dry_density(coupler); } + if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"dycor"); } + if (enable_check_state) { pam_debug_check_state(coupler, 5, nstep); } + + // Sponge layer damping + if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } + coupler.run_module( "sponge_layer", modules::sponge_layer ); + if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sponge"); } + + // Apply hyperdiffusion to account for lack of horizontal mixing in SHOC + pam_hyperdiffusion(coupler); + + // Turbulence - SHOC + coupler.run_module( "compute_surface_friction", modules::compute_surface_friction ); + if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } + coupler.run_module( "sgs", [&] (pam::PamCoupler &coupler) {sgs .timeStep(coupler);} ); + if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"sgs"); } + if (enable_check_state) { pam_debug_check_state(coupler, 6, nstep); } + + // Microphysics - P3 + if (enable_physics_tend_stats) { pam_statistics_save_state(coupler); } + coupler.run_module( "micro", [&] (pam::PamCoupler &coupler) {micro .timeStep(coupler);} ); + if (enable_physics_tend_stats) { pam_statistics_aggregate_tendency(coupler,"micro"); } + if (enable_check_state) { pam_debug_check_state(coupler, 7, nstep); } + + } // num_subcycle // CRM mean state acceleration if (use_crm_accel && !coupler.get_option("crm_acceleration_ceaseflag")) { @@ -227,7 +299,6 @@ extern "C" void pam_driver() { pam_radiation_timestep_aggregation(coupler); pam_statistics_timestep_aggregation(coupler); - etime_crm += crm_dt; nstep += 1; } //------------------------------------------------------------------------------------------------ From 7cc042a07306b2370931de60e03cc077f70f8454 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 13:47:26 -0400 Subject: [PATCH 113/388] bug fix --- components/eam/src/physics/crm/pam/pam_driver.cpp | 2 +- components/eam/src/physics/crm/pam/pam_state.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index 0833d2beff8..a05b5cf8b03 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -83,7 +83,7 @@ inline int pam_driver_set_subcycle_timestep( pam::PamCoupler &coupler, real crm_ if(num_subcycle > max_num_subcycle) { real umax = pmax(uvel_max.data()); real wmax = pmax(wvel_max.data()); - printf("PAM_DRIVER - WARNING: excessive subcycling!"+\ + printf("PAM_DRIVER - WARNING: excessive subcycling!" " - num_subcycle: %3.3d dt: %8.4f cfl: %8.4f umax: %8.2f wmax: %8.2f \n", num_subcycle,crm_dt_subcycle,cfl,umax,wmax); // exit(-1); diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index fb6553df07e..270fef7f6c2 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -189,8 +189,8 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { parallel_for(SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int iens) { if ( hmean_pint(k,iens) < hmean_pmid(k,iens) ) { auto phis = input_phis(iens)/grav; - printf("PAM-STATE - bad interface pressure for reference state - "+\ - "k:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- "+\ + printf("PAM-STATE - bad interface pressure for reference state - " + "k:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- " "pint:%12.4f pmid:%12.4f \n", k,iens,lat(iens),lon(iens),phis, hmean_pint(k,iens),hmean_pmid(k,iens)); From f714cf4e2d6612210692eecdf5b2e4eda3a82933 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 13:48:07 -0400 Subject: [PATCH 114/388] bug fix in PAM variance transport --- .../physics/crm/pam/pam_variance_transport.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_variance_transport.h b/components/eam/src/physics/crm/pam/pam_variance_transport.h index e258b3b7f3a..1eb7779f346 100644 --- a/components/eam/src/physics/crm/pam/pam_variance_transport.h +++ b/components/eam/src/physics/crm/pam/pam_variance_transport.h @@ -118,9 +118,9 @@ inline void pam_variance_transport_compute_forcing( pam::PamCoupler &coupler ) { // calculate variance transport forcing parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k_crm, int n) { int k_gcm = gcm_nlev-1-k_crm; - vt_temp_forcing_tend(k_crm,n) = ( gcm_vt_temp(k_gcm,n) - vt_temp(k_crm,n) ) * gcm_dt ; - vt_rhov_forcing_tend(k_crm,n) = ( gcm_vt_rhov(k_gcm,n) - vt_rhov(k_crm,n) ) * gcm_dt ; - vt_uvel_forcing_tend(k_crm,n) = ( gcm_vt_uvel(k_gcm,n) - vt_uvel(k_crm,n) ) * gcm_dt ; + vt_temp_forcing_tend(k_crm,n) = ( gcm_vt_temp(k_gcm,n) - vt_temp(k_crm,n) ) / gcm_dt ; + vt_rhov_forcing_tend(k_crm,n) = ( gcm_vt_rhov(k_gcm,n) - vt_rhov(k_crm,n) ) / gcm_dt ; + vt_uvel_forcing_tend(k_crm,n) = ( gcm_vt_uvel(k_gcm,n) - vt_uvel(k_crm,n) ) / gcm_dt ; }); //------------------------------------------------------------------------------------------------ } @@ -174,9 +174,9 @@ inline void pam_variance_transport_apply_forcing( pam::PamCoupler &coupler ) { real tmp_t_scale = -1.0; real tmp_q_scale = -1.0; real tmp_u_scale = -1.0; - if (vt_temp(k,n)>0.0) { tmp_t_scale = 1. + crm_dt*vt_temp_forcing_tend(k,n) / vt_temp(k,n); } - if (vt_rhov(k,n)>0.0) { tmp_q_scale = 1. + crm_dt*vt_rhov_forcing_tend(k,n) / vt_rhov(k,n); } - if (vt_uvel(k,n)>0.0) { tmp_u_scale = 1. + crm_dt*vt_uvel_forcing_tend(k,n) / vt_uvel(k,n); } + if (vt_temp(k,n)>0.0) { tmp_t_scale = 1. + crm_dt * vt_temp_forcing_tend(k,n) / vt_temp(k,n); } + if (vt_rhov(k,n)>0.0) { tmp_q_scale = 1. + crm_dt * vt_rhov_forcing_tend(k,n) / vt_rhov(k,n); } + if (vt_uvel(k,n)>0.0) { tmp_u_scale = 1. + crm_dt * vt_uvel_forcing_tend(k,n) / vt_uvel(k,n); } if (tmp_t_scale>0.0){ temp_pert_scale(k,n) = sqrt(tmp_t_scale); } if (tmp_q_scale>0.0){ rhov_pert_scale(k,n) = sqrt(tmp_q_scale); } if (tmp_u_scale>0.0){ uvel_pert_scale(k,n) = sqrt(tmp_u_scale); } @@ -236,9 +236,9 @@ inline void pam_variance_transport_compute_feedback( pam::PamCoupler &coupler ) parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k_crm, int n) { int k_gcm = gcm_nlev-1-k_crm; if (k_crm Date: Fri, 12 Apr 2024 13:48:58 -0400 Subject: [PATCH 115/388] update default MMF_PAM_dyn_per_phys --- components/eam/bld/namelist_files/namelist_defaults_eam.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/bld/namelist_files/namelist_defaults_eam.xml b/components/eam/bld/namelist_files/namelist_defaults_eam.xml index 74f2572ea04..d7e9afecf20 100755 --- a/components/eam/bld/namelist_files/namelist_defaults_eam.xml +++ b/components/eam/bld/namelist_files/namelist_defaults_eam.xml @@ -871,7 +871,7 @@ 0 .false. .true. - 2 + 1 90.0 0.0 From 98a6e4025e9617bfdd0ba27699fa69bbbd959772 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 15:22:03 -0400 Subject: [PATCH 116/388] update default PAM hyperdiffusion timescale --- components/eam/src/physics/crm/pam/pam_hyperdiffusion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h index b632b0e4909..e75d8026544 100644 --- a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h +++ b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h @@ -28,7 +28,7 @@ inline void pam_hyperdiffusion( pam::PamCoupler &coupler ) { #ifdef MMF_PAM_HDT real constexpr hd_timescale = MMF_PAM_HDT; // damping time scale [sec] #else - real constexpr hd_timescale = 60.0; // damping time scale [sec] + real constexpr hd_timescale = 120.0; // damping time scale [sec] #endif //------------------------------------------------------------------------------------------------ real4d hd_temp("hd_temp",nz,ny,nx,nens); From 2c54c4d9aa7db1659374433517d7a2636357c690 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 12 Apr 2024 15:22:46 -0400 Subject: [PATCH 117/388] update PAM default crm_dx to 3km --- components/eam/cime_config/config_component.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/cime_config/config_component.xml b/components/eam/cime_config/config_component.xml index 056b607953f..ef9433ef966 100755 --- a/components/eam/cime_config/config_component.xml +++ b/components/eam/cime_config/config_component.xml @@ -76,7 +76,7 @@ -crm pam -pam_dycor awfl -crm_dt 10 -use_MMF -nlev 60 -crm_nz 50 -crm_dx 2000 -crm_nx 64 -crm_ny 1 -crm_nx_rad 4 -crm_ny_rad 1 - -crm_dx 2000 -crm_nx 45 -crm_ny 1 -crm_nx_rad 5 -crm_ny_rad 1 + -crm_dx 3000 -crm_nx 45 -crm_ny 1 -crm_nx_rad 5 -crm_ny_rad 1 -MMF_microphysics_scheme sam1mom -chem none -MMF_microphysics_scheme p3 -chem none -rad rrtmgp -rrtmgpxx From 289951d1eb76f89b40a77fde44d1ea46ce153b61 Mon Sep 17 00:00:00 2001 From: Trevor Hillebrand Date: Sat, 13 Apr 2024 08:53:43 -0700 Subject: [PATCH 118/388] Remove icebergs in each RK stage Remove icebergs in each RK stage. When ice-shelves melt through in during an intermedite RK stage, they can leave behind icebergs that will cause the velocity solver to fail. So, we need to remove icebergs before each call to the velocity solver. --- .../src/mode_forward/mpas_li_calving.F | 9 +++++---- .../src/mode_forward/mpas_li_time_integration_fe_rk.F | 9 ++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F index de2a523e933..a460c3224a0 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_calving.F @@ -45,7 +45,8 @@ module li_calving !-------------------------------------------------------------------- public :: li_calve_ice, li_restore_calving_front, li_apply_front_ablation_velocity, & - li_calculate_damage, li_finalize_damage_after_advection, li_flood_fill + li_calculate_damage, li_finalize_damage_after_advection, li_flood_fill, & + li_remove_icebergs !-------------------------------------------------------------------- ! @@ -325,7 +326,7 @@ subroutine li_calve_ice(domain, err, solveVeloAfterCalving) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) ! now also remove any icebergs - call remove_icebergs(domain) + call li_remove_icebergs(domain) call li_calculate_mask(meshPool, velocityPool, geometryPool, err_tmp) @@ -4208,7 +4209,7 @@ subroutine calculate_calving_front_mask(meshPool, geometryPool, calvingFrontMask end subroutine calculate_calving_front_mask - subroutine remove_icebergs(domain) + subroutine li_remove_icebergs(domain) !----------------------------------------------------------------- ! input/output variables !----------------------------------------------------------------- @@ -4362,7 +4363,7 @@ subroutine remove_icebergs(domain) call mpas_deallocate_scratch_field(growMaskField, single_block_in=.false.) call mpas_log_write("Iceberg-detection flood-fill complete. Removed $i iceberg cells.", intArgs=(/globalIcebergCellCount/)) call mpas_timer_stop("iceberg detection") - end subroutine remove_icebergs + end subroutine li_remove_icebergs !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_time_integration_fe_rk.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_time_integration_fe_rk.F index 6ca13f8deb0..e4c58cc42b1 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_time_integration_fe_rk.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_time_integration_fe_rk.F @@ -29,7 +29,9 @@ module li_time_integration_fe_rk use mpas_log use li_advection - use li_calving, only: li_calve_ice, li_restore_calving_front, li_calculate_damage, li_finalize_damage_after_advection + use li_calving, only: li_calve_ice, li_restore_calving_front, & + li_remove_icebergs, li_calculate_damage, & + li_finalize_damage_after_advection use li_thermal, only: li_thermal_solver, li_enthalpy_to_temperature_kelvin use li_iceshelf_melt use li_diagnostic_vars @@ -481,6 +483,11 @@ subroutine li_time_integrator_forwardeuler_rungekutta(domain, err) call li_restore_calving_front(domain, err_tmp) err = ior(err, err_tmp) endif + ! We need to remove icebergs between RK stages because the + ! main calving routine is not called until after the RK loop. + ! This frequently results in icebergs that causes intermediate + ! RK stage velocity solves to fail. + call li_remove_icebergs(domain) call li_velocity_solve(domain, solveVelo=.true., err=err_tmp) err = ior(err, err_tmp) From ce8ef3942e5e3134a68a7f7101be7bb21093fd01 Mon Sep 17 00:00:00 2001 From: Jon Wolfe Date: Mon, 15 Apr 2024 11:40:35 -0500 Subject: [PATCH 119/388] Add TL319_r05_IcoswISC30E3r5 configuration --- cime_config/config_grids.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index 909db8f42ef..847cf0e5e69 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -519,6 +519,16 @@ ARRM10to60E2r1 + + TL319 + r05 + IcoswISC30E3r5 + r05 + null + null + IcoswISC30E3r5 + + TL319 TL319 From 434bd3cf3bec69cf37e8bc2a46e2eed82b623c00 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 15 Apr 2024 16:06:36 -0700 Subject: [PATCH 120/388] fix formulation of zonal mean terms for TEM output --- components/eam/src/physics/cam/phys_grid_ctem.F90 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index 470264a6681..80684b30d6d 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -236,6 +236,8 @@ end subroutine phys_grid_ctem_init !----------------------------------------------------------------------------- !----------------------------------------------------------------------------- subroutine phys_grid_ctem_diags(phys_state) + use physconst, only: rair, cpair + type(physics_state), intent(in) :: phys_state(begchunk:endchunk) character(len=*), parameter :: prefix = 'phys_grid_ctem_diags: ' @@ -275,7 +277,6 @@ subroutine phys_grid_ctem_diags(phys_state) real(r8) :: thza(nzalat,pver) real(r8) :: mbarv ! molecular weight of dry air (g/mol) - real(r8) :: sheight(pcols,pver) ! pressure scale height (m) if (.not.do_calc()) return @@ -287,14 +288,11 @@ subroutine phys_grid_ctem_diags(phys_state) ncol = phys_state(lchnk)%ncol - ! scale height - sheight(:ncol,:) = phys_state(lchnk)%t(:ncol,:) * rgas / ( mbarv * grav ) ! meters - ! potential temperature - theta(:ncol,:,lchnk) = phys_state(lchnk)%t(:ncol,:) * phys_state(lchnk)%exner(:ncol,:) + theta(:ncol,:,lchnk) = phys_state(lchnk)%t(:ncol,:) * ( 1000e2 / phys_state(lchnk)%pmid(:ncol,:) )**(rair/cpair) - ! vertical velocity - w(:ncol,:,lchnk) = -sheight(:ncol,:) * phys_state(lchnk)%omega(:ncol,:) / phys_state(lchnk)%pmid(:ncol,:) + ! vertical pressure velocity + w(:ncol,:,lchnk) = phys_state(lchnk)%omega(:ncol,:) u(:ncol,:,lchnk) = phys_state(lchnk)%u(:ncol,:) v(:ncol,:,lchnk) = phys_state(lchnk)%v(:ncol,:) From 748ad0a808b404ebb3cb43b5032c7f663c3cf177 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 17 Apr 2024 18:58:56 -0400 Subject: [PATCH 121/388] reduce hd_timescale back to 60 sec fr PAM --- components/eam/src/physics/crm/pam/pam_hyperdiffusion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h index e75d8026544..b632b0e4909 100644 --- a/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h +++ b/components/eam/src/physics/crm/pam/pam_hyperdiffusion.h @@ -28,7 +28,7 @@ inline void pam_hyperdiffusion( pam::PamCoupler &coupler ) { #ifdef MMF_PAM_HDT real constexpr hd_timescale = MMF_PAM_HDT; // damping time scale [sec] #else - real constexpr hd_timescale = 120.0; // damping time scale [sec] + real constexpr hd_timescale = 60.0; // damping time scale [sec] #endif //------------------------------------------------------------------------------------------------ real4d hd_temp("hd_temp",nz,ny,nx,nens); From 6b92cabe43740e3a36df9c7aa718d9a5a4bc0301 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 17 Apr 2024 18:59:54 -0400 Subject: [PATCH 122/388] update PAM submodule --- components/eam/src/physics/crm/pam/external | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/external b/components/eam/src/physics/crm/pam/external index ff652f3f2a6..8f9538db713 160000 --- a/components/eam/src/physics/crm/pam/external +++ b/components/eam/src/physics/crm/pam/external @@ -1 +1 @@ -Subproject commit ff652f3f2a6c2d675cd957883245aa6c036ef110 +Subproject commit 8f9538db7138baf26fa2b0f163fae3050d3fe29d From f750a1d9caca3e853a215fbf012888d07bba3176 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 18 Apr 2024 16:23:30 -0400 Subject: [PATCH 123/388] make PAM dry density acceleration optional --- .../eam/src/physics/crm/pam/pam_accelerate.h | 89 +++++++++---------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_accelerate.h b/components/eam/src/physics/crm/pam/pam_accelerate.h index a7b179a85c9..5b277fdca96 100644 --- a/components/eam/src/physics/crm/pam/pam_accelerate.h +++ b/components/eam/src/physics/crm/pam/pam_accelerate.h @@ -17,16 +17,22 @@ inline void pam_accelerate_init( pam::PamCoupler &coupler ) { using yakl::c::parallel_for; using yakl::c::SimpleBounds; using yakl::atomicAdd; + //------------------------------------------------------------------------------------------------ + // The ability to accelerate dry density is implemented, but tests suggested + // that this was contributing to instabilities in PAM. Combined with the + // uncertainty of how to handle dry density in the anelastic case, we will + // disable dry density mean-state acceleration by default. + coupler.set_option("crm_accel_rd",false); + //------------------------------------------------------------------------------------------------ auto &dm_device = coupler.get_data_manager_device_readwrite(); auto nens = coupler.get_option("ncrms"); auto nz = coupler.get_option("crm_nz"); auto ny = coupler.get_option("crm_ny"); auto nx = coupler.get_option("crm_nx"); - auto crm_accel_uv = coupler.get_option("crm_accel_uv"); //------------------------------------------------------------------------------------------------ dm_device.register_and_allocate("accel_save_t", "saved temperature for MSA", {nz,nens}, {"z","nens"} ); - // dm_device.register_and_allocate("accel_save_r", "saved dry density for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_q", "saved total water for MSA", {nz,nens}, {"z","nens"} ); + dm_device.register_and_allocate("accel_save_r", "saved dry density for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_u", "saved uvel for MSA", {nz,nens}, {"z","nens"} ); dm_device.register_and_allocate("accel_save_v", "saved vvel for MSA", {nz,nens}, {"z","nens"} ); //------------------------------------------------------------------------------------------------ @@ -42,40 +48,37 @@ inline void pam_accelerate_diagnose( pam::PamCoupler &coupler ) { auto nz = coupler.get_option("crm_nz"); auto ny = coupler.get_option("crm_ny"); auto nx = coupler.get_option("crm_nx"); + auto crm_accel_rd = coupler.get_option("crm_accel_rd"); auto crm_accel_uv = coupler.get_option("crm_accel_uv"); //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); - // auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhol = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice" ); + auto rhod = dm_device.get("density_dry"); auto uvel = dm_device.get("uvel" ); auto vvel = dm_device.get("vvel" ); auto accel_save_t = dm_device.get("accel_save_t"); - // auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_q = dm_device.get("accel_save_q"); + auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_u = dm_device.get("accel_save_u"); auto accel_save_v = dm_device.get("accel_save_v"); //------------------------------------------------------------------------------------------------ // compute horizontal means needed later for mean-state acceleration parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { accel_save_t(k,n) = 0.0; - // accel_save_r(k,n) = 0.0; accel_save_q(k,n) = 0.0; - if (crm_accel_uv) { - accel_save_u(k,n) = 0.0; - accel_save_v(k,n) = 0.0; - } + if (crm_accel_rd) { accel_save_r(k,n) = 0.0; } + if (crm_accel_uv) { accel_save_u(k,n) = 0.0; } + if (crm_accel_uv) { accel_save_v(k,n) = 0.0; } }); real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { yakl::atomicAdd( accel_save_t(k,n), temp(k,j,i,n) * r_nx_ny ); - // yakl::atomicAdd( accel_save_r(k,n), rhod(k,j,i,n) * r_nx_ny ); yakl::atomicAdd( accel_save_q(k,n), ( rhov(k,j,i,n) + rhol(k,j,i,n) + rhoi(k,j,i,n) ) * r_nx_ny ); - if (crm_accel_uv) { - yakl::atomicAdd( accel_save_u(k,n), uvel(k,j,i,n) * r_nx_ny ); - yakl::atomicAdd( accel_save_v(k,n), vvel(k,j,i,n) * r_nx_ny ); - } + if (crm_accel_rd) { yakl::atomicAdd( accel_save_r(k,n), rhod(k,j,i,n) * r_nx_ny ); } + if (crm_accel_uv) { yakl::atomicAdd( accel_save_u(k,n), uvel(k,j,i,n) * r_nx_ny ); } + if (crm_accel_uv) { yakl::atomicAdd( accel_save_v(k,n), vvel(k,j,i,n) * r_nx_ny ); } }); //------------------------------------------------------------------------------------------------ } @@ -86,35 +89,35 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { using yakl::c::SimpleBounds; using yakl::atomicAdd; using yakl::ScalarLiveOut; - auto &dm_device = coupler.get_data_manager_device_readwrite(); - auto nens = coupler.get_option("ncrms"); - auto nz = coupler.get_option("crm_nz"); - auto ny = coupler.get_option("crm_ny"); - auto nx = coupler.get_option("crm_nx"); + auto &dm_device = coupler.get_data_manager_device_readwrite(); + auto nens = coupler.get_option("ncrms"); + auto nz = coupler.get_option("crm_nz"); + auto ny = coupler.get_option("crm_ny"); + auto nx = coupler.get_option("crm_nx"); + auto crm_accel_rd = coupler.get_option("crm_accel_rd"); + auto crm_accel_uv = coupler.get_option("crm_accel_uv"); + real crm_accel_factor = coupler.get_option("crm_accel_factor"); //------------------------------------------------------------------------------------------------ auto temp = dm_device.get("temp" ); - // auto rhod = dm_device.get("density_dry"); auto rhov = dm_device.get("water_vapor"); auto rhol = dm_device.get("cloud_water"); auto rhoi = dm_device.get("ice" ); + auto rhod = dm_device.get("density_dry"); auto uvel = dm_device.get("uvel" ); auto vvel = dm_device.get("vvel" ); auto accel_save_t = dm_device.get("accel_save_t"); - // auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_q = dm_device.get("accel_save_q"); + auto accel_save_r = dm_device.get("accel_save_r"); auto accel_save_u = dm_device.get("accel_save_u"); auto accel_save_v = dm_device.get("accel_save_v"); //------------------------------------------------------------------------------------------------ - bool crm_accel_uv = coupler.get_option("crm_accel_uv"); - real crm_accel_factor = coupler.get_option("crm_accel_factor"); - //------------------------------------------------------------------------------------------------ real2d hmean_t ("hmean_t", nz,nens); - // real2d hmean_r ("hmean_r", nz,nens); + real2d hmean_r ("hmean_r", nz,nens); real2d hmean_q ("hmean_q", nz,nens); real2d hmean_u ("hmean_u", nz,nens); real2d hmean_v ("hmean_v", nz,nens); real2d ttend_acc("ttend_acc", nz,nens); - // real2d rtend_acc("rtend_acc", nz,nens); + real2d rtend_acc("rtend_acc", nz,nens); real2d qtend_acc("qtend_acc", nz,nens); real2d utend_acc("utend_acc", nz,nens); real2d vtend_acc("vtend_acc", nz,nens); @@ -127,22 +130,18 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { // Compute the horizontal mean for each variable parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { hmean_t(k,n) = 0.0; - // hmean_r(k,n) = 0.0; hmean_q(k,n) = 0.0; - if (crm_accel_uv) { - hmean_u(k,n) = 0.0; - hmean_v(k,n) = 0.0; - } + if (crm_accel_rd) { hmean_r(k,n) = 0.0; } + if (crm_accel_uv) { hmean_u(k,n) = 0.0; } + if (crm_accel_uv) { hmean_v(k,n) = 0.0; } }); real r_nx_ny = 1._fp/(nx*ny); // precompute reciprocal to avoid costly divisions parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { yakl::atomicAdd( hmean_t(k,n), temp(k,j,i,n) * r_nx_ny ); - // yakl::atomicAdd( hmean_r(k,n), rhod(k,j,i,n) * r_nx_ny ); yakl::atomicAdd( hmean_q(k,n), ( rhov(k,j,i,n) + rhol(k,j,i,n) + rhoi(k,j,i,n) ) * r_nx_ny ); - if (crm_accel_uv) { - yakl::atomicAdd( hmean_u(k,n), uvel(k,j,i,n) * r_nx_ny ); - yakl::atomicAdd( hmean_v(k,n), vvel(k,j,i,n) * r_nx_ny ); - } + if (crm_accel_rd) { yakl::atomicAdd( hmean_r(k,n), rhod(k,j,i,n) * r_nx_ny ); } + if (crm_accel_uv) { yakl::atomicAdd( hmean_u(k,n), uvel(k,j,i,n) * r_nx_ny ); } + if (crm_accel_uv) { yakl::atomicAdd( hmean_v(k,n), vvel(k,j,i,n) * r_nx_ny ); } }); //------------------------------------------------------------------------------------------------ // Compute the accelerated tendencies @@ -150,12 +149,10 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { ScalarLiveOut ceaseflag_liveout(false); parallel_for( SimpleBounds<2>(nz,nens) , YAKL_LAMBDA (int k, int n) { ttend_acc(k,n) = hmean_t(k,n) - accel_save_t(k,n); - // rtend_acc(k,n) = hmean_r(k,n) - accel_save_r(k,n); qtend_acc(k,n) = hmean_q(k,n) - accel_save_q(k,n); - if (crm_accel_uv) { - utend_acc(k,n) = hmean_u(k,n) - accel_save_u(k,n); - vtend_acc(k,n) = hmean_v(k,n) - accel_save_v(k,n); - } + if (crm_accel_rd) { rtend_acc(k,n) = hmean_r(k,n) - accel_save_r(k,n); } + if (crm_accel_uv) { utend_acc(k,n) = hmean_u(k,n) - accel_save_u(k,n); } + if (crm_accel_uv) { vtend_acc(k,n) = hmean_v(k,n) - accel_save_v(k,n); } if (abs(ttend_acc(k,n)) > dtemp_max) { ceaseflag_liveout = true; } @@ -191,14 +188,11 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { //------------------------------------------------------------------------------------------------ // Apply the accelerated tendencies parallel_for( SimpleBounds<4>(nz,ny,nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { - temp(k,j,i,n) = temp(k,j,i,n) + crm_accel_factor * ttend_acc(k,n); - // rhod(k,j,i,n) = rhod(k,j,i,n) + crm_accel_factor * rtend_acc(k,n); rhov(k,j,i,n) = rhov(k,j,i,n) + crm_accel_factor * qtend_acc(k,n); - if (crm_accel_uv) { - uvel(k,j,i,n) = uvel(k,j,i,n) + crm_accel_factor * utend_acc(k,n); - vvel(k,j,i,n) = vvel(k,j,i,n) + crm_accel_factor * vtend_acc(k,n); - } + if (crm_accel_rd) { rhod(k,j,i,n) = rhod(k,j,i,n) + crm_accel_factor * rtend_acc(k,n); } + if (crm_accel_uv) { uvel(k,j,i,n) = uvel(k,j,i,n) + crm_accel_factor * utend_acc(k,n); } + if (crm_accel_uv) { vvel(k,j,i,n) = vvel(k,j,i,n) + crm_accel_factor * vtend_acc(k,n); } // apply limiter on temperature temp(k,j,i,n) = std::max( temp_min, temp(k,j,i,n) ); }); @@ -231,4 +225,3 @@ inline void pam_accelerate( pam::PamCoupler &coupler, int nstep, int &nstop ) { }); //------------------------------------------------------------------------------------------------ } - From 8e65b050739206ac2490374af86e0721562194a8 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 18 Apr 2024 16:24:38 -0400 Subject: [PATCH 124/388] remove MMF_PAM_dyn_per_phys namelist option --- components/eam/bld/build-namelist | 3 --- .../eam/bld/namelist_files/namelist_defaults_eam.xml | 1 - components/eam/bld/namelist_files/namelist_definition.xml | 6 ------ components/eam/src/physics/cam/phys_control.F90 | 8 ++------ components/eam/src/physics/crm/crm_physics.F90 | 7 ------- components/eam/src/physics/crm/pam/pam_driver.cpp | 1 + 6 files changed, 3 insertions(+), 23 deletions(-) diff --git a/components/eam/bld/build-namelist b/components/eam/bld/build-namelist index ac9001c3f7b..8dc532b6a3d 100755 --- a/components/eam/bld/build-namelist +++ b/components/eam/bld/build-namelist @@ -3941,9 +3941,6 @@ if ($cfg->get('use_MMF')) { # MMF CRM domain orientation add_default($nl, 'MMF_orientation_angle'); - - # PAM dynamics sub-stepping parameter - add_default($nl, 'MMF_PAM_dyn_per_phys'); } add_default($nl, 'do_aerocom_ind3'); diff --git a/components/eam/bld/namelist_files/namelist_defaults_eam.xml b/components/eam/bld/namelist_files/namelist_defaults_eam.xml index d7e9afecf20..fd7a91f19a1 100755 --- a/components/eam/bld/namelist_files/namelist_defaults_eam.xml +++ b/components/eam/bld/namelist_files/namelist_defaults_eam.xml @@ -871,7 +871,6 @@ 0 .false. .true. - 1 90.0 0.0 diff --git a/components/eam/bld/namelist_files/namelist_definition.xml b/components/eam/bld/namelist_files/namelist_definition.xml index cc59697d5bb..19e356ca6cc 100644 --- a/components/eam/bld/namelist_files/namelist_definition.xml +++ b/components/eam/bld/namelist_files/namelist_definition.xml @@ -4824,12 +4824,6 @@ Defaults: 3D CRM: 0 - -Number of PAM dycor calls per physics time step. -Default: 2 - - Wavenumber cutoff for filtered MMF variance transport. diff --git a/components/eam/src/physics/cam/phys_control.F90 b/components/eam/src/physics/cam/phys_control.F90 index b87ea442c4e..b7c9b37fa81 100644 --- a/components/eam/src/physics/cam/phys_control.F90 +++ b/components/eam/src/physics/cam/phys_control.F90 @@ -72,7 +72,6 @@ module phys_control logical :: use_crm_accel = .false. ! true => use MMF CRM mean-state acceleration (MSA) real(r8) :: crm_accel_factor = 2.D0 ! CRM acceleration factor logical :: crm_accel_uv = .true. ! true => apply MMF CRM MSA to momentum fields -integer :: MMF_PAM_dyn_per_phys = 2 ! PAM CRM dynamics steps per CRM physics steps logical :: use_subcol_microp = .false. ! if .true. then use sub-columns in microphysics @@ -229,7 +228,7 @@ subroutine phys_ctl_readnl(nlfile) eddy_scheme, microp_scheme, macrop_scheme, radiation_scheme, srf_flux_avg, & MMF_microphysics_scheme, MMF_orientation_angle, use_MMF, use_ECPP, & use_MMF_VT, MMF_VT_wn_max, use_MMF_ESMT, & - use_crm_accel, crm_accel_factor, crm_accel_uv, MMF_PAM_dyn_per_phys, & + use_crm_accel, crm_accel_factor, crm_accel_uv, & use_subcol_microp, atm_dep_flux, history_amwg, history_verbose, history_vdiag, & get_presc_aero_data,history_aerosol, history_aero_optics, & is_output_interactive_volc, & @@ -314,7 +313,6 @@ subroutine phys_ctl_readnl(nlfile) call mpibcast(use_crm_accel, 1 , mpilog, 0, mpicom) call mpibcast(crm_accel_factor, 1 , mpir8, 0, mpicom) call mpibcast(crm_accel_uv, 1 , mpilog, 0, mpicom) - call mpibcast(MMF_PAM_dyn_per_phys, 1 , mpiint, 0, mpicom) call mpibcast(use_subcol_microp, 1 , mpilog, 0, mpicom) call mpibcast(atm_dep_flux, 1 , mpilog, 0, mpicom) call mpibcast(history_amwg, 1 , mpilog, 0, mpicom) @@ -598,7 +596,7 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & prog_modal_aero_out, macrop_scheme_out, ideal_phys_option_out, & use_MMF_out, use_ECPP_out, MMF_microphysics_scheme_out, & MMF_orientation_angle_out, use_MMF_VT_out, MMF_VT_wn_max_out, use_MMF_ESMT_out, & - use_crm_accel_out, crm_accel_factor_out, crm_accel_uv_out, MMF_PAM_dyn_per_phys_out, & + use_crm_accel_out, crm_accel_factor_out, crm_accel_uv_out, & do_clubb_sgs_out, do_shoc_sgs_out, do_tms_out, state_debug_checks_out, & linearize_pbl_winds_out, & do_aerocom_ind3_out, & @@ -641,7 +639,6 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & logical, intent(out), optional :: use_crm_accel_out real(r8), intent(out), optional :: crm_accel_factor_out logical, intent(out), optional :: crm_accel_uv_out - integer, intent(out), optional :: MMF_PAM_dyn_per_phys_out logical, intent(out), optional :: use_subcol_microp_out logical, intent(out), optional :: atm_dep_flux_out logical, intent(out), optional :: history_amwg_out @@ -745,7 +742,6 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, & if ( present(use_crm_accel_out ) ) use_crm_accel_out = use_crm_accel if ( present(crm_accel_factor_out ) ) crm_accel_factor_out = crm_accel_factor if ( present(crm_accel_uv_out ) ) crm_accel_uv_out = crm_accel_uv - if ( present(MMF_PAM_dyn_per_phys_out) ) MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys if ( present(use_subcol_microp_out ) ) use_subcol_microp_out = use_subcol_microp if ( present(macrop_scheme_out ) ) macrop_scheme_out = macrop_scheme diff --git a/components/eam/src/physics/crm/crm_physics.F90 b/components/eam/src/physics/crm/crm_physics.F90 index 51628d5ea74..39ed6a0876c 100644 --- a/components/eam/src/physics/crm/crm_physics.F90 +++ b/components/eam/src/physics/crm/crm_physics.F90 @@ -620,8 +620,6 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, logical :: use_MMF_VT_tmp ! flag for MMF variance transport (for Fortran CRM) logical :: use_MMF_ESMT_tmp ! flag for MMF scalar momentum transport (for Fortran CRM) integer :: MMF_VT_wn_max ! wavenumber cutoff for filtered variance transport - - integer :: MMF_PAM_dyn_per_phys ! PAM CRM dynamics steps per CRM physics steps real(r8) :: tmp_e_sat ! temporary saturation vapor pressure real(r8) :: tmp_q_sat ! temporary saturation specific humidity @@ -734,9 +732,6 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, use_crm_accel = use_crm_accel_tmp crm_accel_uv = crm_accel_uv_tmp - ! PAM namelist options - call phys_getopts(MMF_PAM_dyn_per_phys_out = MMF_PAM_dyn_per_phys) - nstep = get_nstep() itim = pbuf_old_tim_idx() ! "Old" pbuf time index (what does all this mean?) @@ -1466,8 +1461,6 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf2d, cam_in, cam_out, call pam_set_option('enable_physics_tend_stats', .false. ) - call pam_set_option('crm_dyn_per_phys', MMF_PAM_dyn_per_phys ) - call pam_set_option('is_first_step', (nstep<=1) ) call pam_set_option('is_restart', (nsrest>0) ) call pam_set_option('am_i_root', masterproc ) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index a05b5cf8b03..f8f575ec8a1 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -122,6 +122,7 @@ extern "C" void pam_driver() { coupler.set_option("crm_acceleration_ceaseflag",false); //------------------------------------------------------------------------------------------------ // coupler options for SPAM dycor + coupler.set_option("crm_dyn_per_phys",1); coupler.set_option("spam_couple_wind_exact_inverse",true); coupler.set_option("spam_clip_negative_densities",true); coupler.set_option("spam_clip_vertical_velocities",true); From 743b8ff2bdcc8a50672e5135ea3fa5c2e6a4ea4d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 18 Apr 2024 16:26:14 -0400 Subject: [PATCH 125/388] fix white space --- components/eam/bld/namelist_files/namelist_defaults_eam.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/components/eam/bld/namelist_files/namelist_defaults_eam.xml b/components/eam/bld/namelist_files/namelist_defaults_eam.xml index fd7a91f19a1..56c816b1753 100755 --- a/components/eam/bld/namelist_files/namelist_defaults_eam.xml +++ b/components/eam/bld/namelist_files/namelist_defaults_eam.xml @@ -871,6 +871,7 @@ 0 .false. .true. + 90.0 0.0 From 56c11f70c5137f887f204d00cd6bd7de9ed9e29a Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 18 Apr 2024 16:37:56 -0400 Subject: [PATCH 126/388] pam_debug.h clean-up --- .../eam/src/physics/crm/pam/pam_debug.h | 235 ++++++++++-------- 1 file changed, 129 insertions(+), 106 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_debug.h b/components/eam/src/physics/crm/pam/pam_debug.h index 43d2b5bf4f5..7e54f437f69 100644 --- a/components/eam/src/physics/crm/pam/pam_debug.h +++ b/components/eam/src/physics/crm/pam/pam_debug.h @@ -91,121 +91,144 @@ void pam_debug_check_state( pam::PamCoupler &coupler, int id, int nstep ) { auto input_phis = dm_host.get("input_phis").createDeviceCopy(); real grav = 9.80616; //------------------------------------------------------------------------------------------------ + // logical switches to set which checks are active + bool chk_nan = true; // check for NaN values in select fields + bool chk_neg = true; // check for negative values in select fields + bool chk_low_t = false; // check for low temperatures + bool chk_drop_t = true; // check for large drops in temperature + bool chk_wvel = false; // check for large vertical velocity + //------------------------------------------------------------------------------------------------ // Check for invalid values parallel_for("", SimpleBounds<4>(nz,ny,nx,nens), YAKL_LAMBDA (int k, int j, int i, int iens) { auto phis = input_phis(iens)/grav; + //-------------------------------------------------------------------------- // Check for NaNs - const auto is_nan_t_atm = isnan( temp(k,j,i,iens) ); - const auto is_nan_d_atm = isnan( rhod(k,j,i,iens) ); - const auto is_nan_q_atm = isnan( rhov(k,j,i,iens) ); - if ( is_nan_t_atm || is_nan_q_atm || is_nan_d_atm ) { - auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - nstep,id,k,i,iens,lat(iens),lon(iens),phis, - temp(k,j,i,iens), - rhod(k,j,i,iens), - rhov(k,j,i,iens), - rhoc(k,j,i,iens), - rhoi(k,j,i,iens), - uvel(k,j,i,iens), - wvel(k,j,i,iens), - debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), - debug_save_rhov(k,j,i,iens), - debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens), - debug_save_uvel(k,j,i,iens), - debug_save_wvel(k,j,i,iens) - ); + if (chk_nan) { + const auto is_nan_t_atm = isnan( temp(k,j,i,iens) ); + const auto is_nan_d_atm = isnan( rhod(k,j,i,iens) ); + const auto is_nan_q_atm = isnan( rhov(k,j,i,iens) ); + if ( is_nan_t_atm || is_nan_q_atm || is_nan_d_atm ) { + auto phis = input_phis(iens)/grav; + printf("PAM-DEBUG nan-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhod(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } } + //-------------------------------------------------------------------------- // Check for negative values - const auto is_neg_t_atm = temp(k,j,i,iens)<0; - const auto is_neg_d_atm = rhod(k,j,i,iens)<0; - const auto is_neg_q_atm = rhov(k,j,i,iens)<0; - if ( is_neg_t_atm || is_neg_q_atm || is_neg_d_atm ) { - auto phis = input_phis(iens)/grav; - printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - nstep,id,k,i,iens,lat(iens),lon(iens),phis, - temp(k,j,i,iens), - rhod(k,j,i,iens), - rhov(k,j,i,iens), - rhoc(k,j,i,iens), - rhoi(k,j,i,iens), - uvel(k,j,i,iens), - wvel(k,j,i,iens), - debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), - debug_save_rhov(k,j,i,iens), - debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens), - debug_save_uvel(k,j,i,iens), - debug_save_wvel(k,j,i,iens) - ); + if (chk_neg) { + const auto is_neg_t_atm = temp(k,j,i,iens)<0; + const auto is_neg_d_atm = rhod(k,j,i,iens)<0; + const auto is_neg_q_atm = rhov(k,j,i,iens)<0; + if ( is_neg_t_atm || is_neg_q_atm || is_neg_d_atm ) { + auto phis = input_phis(iens)/grav; + printf("PAM-DEBUG neg-found - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhod(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } + } + //-------------------------------------------------------------------------- + // Check for low temperature + if (chk_low_t) { + const auto is_low_t = temp(k,j,i,iens)<100; + if ( is_low_t ) { + printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhod(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } } - // // Check for low temperature - // const auto is_low_t = temp(k,j,i,iens)<100; - // if ( is_low_t ) { - // printf("PAM-DEBUG low-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - // nstep,id,k,i,iens,lat(iens),lon(iens),phis, - // temp(k,j,i,iens), - // rhod(k,j,i,iens), - // rhov(k,j,i,iens), - // rhoc(k,j,i,iens), - // rhoi(k,j,i,iens), - // uvel(k,j,i,iens), - // wvel(k,j,i,iens), - // debug_save_temp(k,j,i,iens), - // debug_save_rhod(k,j,i,iens), - // debug_save_rhov(k,j,i,iens), - // debug_save_rhoc(k,j,i,iens), - // debug_save_rhoi(k,j,i,iens), - // debug_save_uvel(k,j,i,iens), - // debug_save_wvel(k,j,i,iens) - // ); - // } + //-------------------------------------------------------------------------- // Check for large temperature drops - const auto is_drop_t = (temp(k,j,i,iens)-debug_save_temp(k,j,i,iens))<-50; - if ( is_drop_t ) { - printf("PAM-DEBUG drop-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - nstep,id,k,i,iens,lat(iens),lon(iens),phis, - temp(k,j,i,iens), - rhod(k,j,i,iens), - rhov(k,j,i,iens), - rhoc(k,j,i,iens), - rhoi(k,j,i,iens), - uvel(k,j,i,iens), - wvel(k,j,i,iens), - debug_save_temp(k,j,i,iens), - debug_save_rhod(k,j,i,iens), - debug_save_rhov(k,j,i,iens), - debug_save_rhoc(k,j,i,iens), - debug_save_rhoi(k,j,i,iens), - debug_save_uvel(k,j,i,iens), - debug_save_wvel(k,j,i,iens) - ); + if (chk_drop_t) { + const auto is_drop_t = (temp(k,j,i,iens)-debug_save_temp(k,j,i,iens))<-50; + if ( is_drop_t ) { + printf("PAM-DEBUG drop-T - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhod(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } + } + //-------------------------------------------------------------------------- + // Check for large vertical velocity + if (chk_wvel) { + const auto is_large_pos_w = wvel(k,j,i,iens)> 40; + const auto is_large_neg_w = wvel(k,j,i,iens)<-40; + if ( is_large_pos_w || is_large_neg_w ) { + printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", + nstep,id,k,i,iens,lat(iens),lon(iens),phis, + temp(k,j,i,iens), + rhod(k,j,i,iens), + rhov(k,j,i,iens), + rhoc(k,j,i,iens), + rhoi(k,j,i,iens), + uvel(k,j,i,iens), + wvel(k,j,i,iens), + debug_save_temp(k,j,i,iens), + debug_save_rhod(k,j,i,iens), + debug_save_rhov(k,j,i,iens), + debug_save_rhoc(k,j,i,iens), + debug_save_rhoi(k,j,i,iens), + debug_save_uvel(k,j,i,iens), + debug_save_wvel(k,j,i,iens) + ); + } } - // // Check for large vertical velocity - // const auto is_large_pos_w = wvel(k,j,i,iens)> 40; - // const auto is_large_neg_w = wvel(k,j,i,iens)<-40; - // if ( is_large_pos_w || is_large_neg_w ) { - // printf("PAM-DEBUG large-W - st:%3.3d id:%2.2d k:%3.3d i:%3.3d n:%3.3d y:%5.1f x:%5.1f ph:%6.1f -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g -- t:%8.2g rd:%8.2g rv:%8.2g rc:%8.2g ri:%8.2g u:%8.2g w:%8.2g \n", - // nstep,id,k,i,iens,lat(iens),lon(iens),phis, - // temp(k,j,i,iens), - // rhod(k,j,i,iens), - // rhov(k,j,i,iens), - // rhoc(k,j,i,iens), - // rhoi(k,j,i,iens), - // uvel(k,j,i,iens), - // wvel(k,j,i,iens), - // debug_save_temp(k,j,i,iens), - // debug_save_rhod(k,j,i,iens), - // debug_save_rhov(k,j,i,iens), - // debug_save_rhoc(k,j,i,iens), - // debug_save_rhoi(k,j,i,iens), - // debug_save_uvel(k,j,i,iens), - // debug_save_wvel(k,j,i,iens) - // ); - // } + //-------------------------------------------------------------------------- // update saved previous values debug_save_temp(k,j,i,iens) = temp(k,j,i,iens); debug_save_rhod(k,j,i,iens) = rhod(k,j,i,iens); From 8eae43e1a3df9f9ddde9a52d37ecad06ec77b199 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 25 Apr 2024 15:13:25 -0400 Subject: [PATCH 127/388] update PAM submodule --- components/eam/src/physics/crm/pam/external | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/external b/components/eam/src/physics/crm/pam/external index 8f9538db713..5931666c95a 160000 --- a/components/eam/src/physics/crm/pam/external +++ b/components/eam/src/physics/crm/pam/external @@ -1 +1 @@ -Subproject commit 8f9538db7138baf26fa2b0f163fae3050d3fe29d +Subproject commit 5931666c95a3b75ae63fbe5bff6e743e74cb2c0a From d8c570fc784dfaedb0120d03650d9f97306c6311 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 30 Apr 2024 12:07:22 -0700 Subject: [PATCH 128/388] add zonal mean surface pressure output --- .../eam/src/physics/cam/phys_grid_ctem.F90 | 86 ++++++++++--------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index 80684b30d6d..11d2adcbcc3 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -221,6 +221,7 @@ subroutine phys_grid_ctem_init if (.not.do_tem_diags) return + call addfld ('PSzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean surface pressure', gridname='ctem_zavg_phys' ) call addfld ('Uzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean zonal wind', gridname='ctem_zavg_phys' ) call addfld ('Vzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean meridional wind', gridname='ctem_zavg_phys' ) call addfld ('Wzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean vertical wind', gridname='ctem_zavg_phys' ) @@ -242,10 +243,14 @@ subroutine phys_grid_ctem_diags(phys_state) character(len=*), parameter :: prefix = 'phys_grid_ctem_diags: ' + real(r8) :: ps(pcols,pver,begchunk:endchunk) + real(r8) :: u(pcols,pver,begchunk:endchunk) real(r8) :: v(pcols,pver,begchunk:endchunk) real(r8) :: w(pcols,pver,begchunk:endchunk) + real(r8) :: pszm(pcols,begchunk:endchunk) + real(r8) :: uzm(pcols,pver,begchunk:endchunk) real(r8) :: vzm(pcols,pver,begchunk:endchunk) real(r8) :: wzm(pcols,pver,begchunk:endchunk) @@ -271,40 +276,37 @@ subroutine phys_grid_ctem_diags(phys_state) real(r8) :: vthza(nzalat,pver) real(r8) :: wthza(nzalat,pver) + real(r8) :: psza(nzalat) real(r8) :: uza(nzalat,pver) real(r8) :: vza(nzalat,pver) real(r8) :: wza(nzalat,pver) real(r8) :: thza(nzalat,pver) - real(r8) :: mbarv ! molecular weight of dry air (g/mol) - - if (.not.do_calc()) return - ! In CESM/WACCM the variable mbarv is provided by the "air_composition" ! module, which is not in E3SM, so we just use a rough approximation - mbarv = 28.97 + real(r8) :: mbarv = 28.97 ! molecular weight of dry air (g/mol) - do lchnk = begchunk,endchunk + if (.not.do_calc()) return + do lchnk = begchunk,endchunk ncol = phys_state(lchnk)%ncol - + ! surface pressure + ps(:ncol,lchnk) = phys_state(lchnk)%ps(:ncol) ! potential temperature theta(:ncol,:,lchnk) = phys_state(lchnk)%t(:ncol,:) * ( 1000e2 / phys_state(lchnk)%pmid(:ncol,:) )**(rair/cpair) - ! vertical pressure velocity w(:ncol,:,lchnk) = phys_state(lchnk)%omega(:ncol,:) - + ! horizontal velocity u(:ncol,:,lchnk) = phys_state(lchnk)%u(:ncol,:) v(:ncol,:,lchnk) = phys_state(lchnk)%v(:ncol,:) - end do ! zonal means evaluated on the physics grid (3D) to be used in the deviations calculation below - uzm(:,:,:) = zmean_fld(u(:,:,:)) - vzm(:,:,:) = zmean_fld(v(:,:,:)) - wzm(:,:,:) = zmean_fld(w(:,:,:)) - thzm(:,:,:) = zmean_fld(theta(:,:,:)) - + pszm(:,:) = zmean_fld_2D(ps(:,:)) + uzm(:,:,:) = zmean_fld_3D(u(:,:,:)) + vzm(:,:,:) = zmean_fld_3D(v(:,:,:)) + wzm(:,:,:) = zmean_fld_3D(w(:,:,:)) + thzm(:,:,:) = zmean_fld_3D(theta(:,:,:)) ! diagnostic output do lchnk = begchunk, endchunk @@ -316,42 +318,44 @@ subroutine phys_grid_ctem_diags(phys_state) do k = 1,pver ! zonal deviations thd(:ncol,k,lchnk) = theta(:ncol,k,lchnk) - thzm(:ncol,k,lchnk) - ud(:ncol,k,lchnk) = u(:ncol,k,lchnk) - uzm(:ncol,k,lchnk) - vd(:ncol,k,lchnk) = v(:ncol,k,lchnk) - vzm(:ncol,k,lchnk) - wd(:ncol,k,lchnk) = w(:ncol,k,lchnk) - wzm(:ncol,k,lchnk) + ud(:ncol,k,lchnk) = u(:ncol,k,lchnk) - uzm(:ncol,k,lchnk) + vd(:ncol,k,lchnk) = v(:ncol,k,lchnk) - vzm(:ncol,k,lchnk) + wd(:ncol,k,lchnk) = w(:ncol,k,lchnk) - wzm(:ncol,k,lchnk) ! fluxes - uvp(:ncol,k,lchnk) = ud(:ncol,k,lchnk) * vd(:ncol,k,lchnk) - uwp(:ncol,k,lchnk) = ud(:ncol,k,lchnk) * wd(:ncol,k,lchnk) + uvp(:ncol,k,lchnk) = ud(:ncol,k,lchnk) * vd(:ncol,k,lchnk) + uwp(:ncol,k,lchnk) = ud(:ncol,k,lchnk) * wd(:ncol,k,lchnk) vthp(:ncol,k,lchnk) = vd(:ncol,k,lchnk) * thd(:ncol,k,lchnk) wthp(:ncol,k,lchnk) = wd(:ncol,k,lchnk) * thd(:ncol,k,lchnk) end do end do ! evaluate and output fluxes on the zonal-average grid - call ZAobj%binAvg(uvp, uvza) - call ZAobj%binAvg(uwp, uwza) + call ZAobj%binAvg(uvp, uvza) + call ZAobj%binAvg(uwp, uwza) call ZAobj%binAvg(vthp, vthza) call ZAobj%binAvg(wthp, wthza) - if (any(abs(uvza)>1.e20_r8)) call endrun(prefix//'bad values in uvza') - if (any(abs(uwza)>1.e20_r8)) call endrun(prefix//'bad values in uwza') + if (any(abs(uvza)>1.e20_r8)) call endrun(prefix//'bad values in uvza') + if (any(abs(uwza)>1.e20_r8)) call endrun(prefix//'bad values in uwza') if (any(abs(vthza)>1.e20_r8)) call endrun(prefix//'bad values in vthza') if (any(abs(wthza)>1.e20_r8)) call endrun(prefix//'bad values in wthza') - call ZAobj%binAvg(uzm, uza) - call ZAobj%binAvg(vzm, vza) - call ZAobj%binAvg(wzm, wza) + call ZAobj%binAvg(pszm, psza) + call ZAobj%binAvg(uzm, uza) + call ZAobj%binAvg(vzm, vza) + call ZAobj%binAvg(wzm, wza) call ZAobj%binAvg(thzm, thza) - - if (any(abs(uza)>1.e20_r8)) call endrun(prefix//'bad values in uza') - if (any(abs(vza)>1.e20_r8)) call endrun(prefix//'bad values in vza') - if (any(abs(wza)>1.e20_r8)) call endrun(prefix//'bad values in wza') + if (any(abs(psza)>1.e20_r8)) call endrun(prefix//'bad values in psza') + if (any(abs(uza)>1.e20_r8)) call endrun(prefix//'bad values in uza') + if (any(abs(vza)>1.e20_r8)) call endrun(prefix//'bad values in vza') + if (any(abs(wza)>1.e20_r8)) call endrun(prefix//'bad values in wza') if (any(abs(thza)>1.e20_r8)) call endrun(prefix//'bad values in thza') ! diagnostic output do j = 1,nzalat + call outfld('PSzm',psza(j),1,j) call outfld('Uzm',uza(j,:),1,j) call outfld('Vzm',vza(j,:),1,j) call outfld('Wzm',wza(j,:),1,j) @@ -367,28 +371,32 @@ subroutine phys_grid_ctem_diags(phys_state) !------------------------------------------------------------------------------ ! utility function for evaluating 3D zonal mean fields !------------------------------------------------------------------------------ - function zmean_fld( fld ) result(fldzm) - + function zmean_fld_3D( fld ) result(fldzm) real(r8), intent(in) :: fld(pcols,pver,begchunk:endchunk) - real(r8) :: fldzm(pcols,pver,begchunk:endchunk) - real(r8) :: Zonal_Bamp3d(nzmbas,pver) - call ZMobj%calc_amps(fld,Zonal_Bamp3d) call ZMobj%eval_grid(Zonal_Bamp3d,fldzm) + end function zmean_fld_3D - end function zmean_fld + !------------------------------------------------------------------------------ + ! utility function for evaluating 2D zonal mean fields + !------------------------------------------------------------------------------ + function zmean_fld_2D( fld ) result(fldzm) + real(r8), intent(in) :: fld(pcols,begchunk:endchunk) + real(r8) :: fldzm(pcols,begchunk:endchunk) + real(r8) :: Zonal_Bamp2d(nzmbas,pver) + call ZMobj%calc_amps(fld,Zonal_Bamp2d) + call ZMobj%eval_grid(Zonal_Bamp2d,fldzm) + end function zmean_fld_2D !------------------------------------------------------------------------------ ! utility function returns TRUE when time to update TEM diags !------------------------------------------------------------------------------ logical function do_calc() - integer :: nstep nstep = get_nstep() do_calc = do_tem_diags .and. mod(nstep,ntimesteps) == 0 - end function do_calc end subroutine phys_grid_ctem_diags From 60a465505302854e6cb36504e684f04b7d540812 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 30 Apr 2024 13:55:39 -0700 Subject: [PATCH 129/388] bug fix --- components/eam/src/physics/cam/phys_grid_ctem.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index 11d2adcbcc3..3941b6c9e41 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -243,7 +243,7 @@ subroutine phys_grid_ctem_diags(phys_state) character(len=*), parameter :: prefix = 'phys_grid_ctem_diags: ' - real(r8) :: ps(pcols,pver,begchunk:endchunk) + real(r8) :: ps(pcols,begchunk:endchunk) real(r8) :: u(pcols,pver,begchunk:endchunk) real(r8) :: v(pcols,pver,begchunk:endchunk) From aaf9e5904fd2466a06c6c12ae1b7ac3443ac0533 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 30 Apr 2024 15:57:07 -0700 Subject: [PATCH 130/388] bug fix --- components/eam/src/physics/cam/phys_grid_ctem.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index 3941b6c9e41..1f8172dd52c 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -385,7 +385,7 @@ end function zmean_fld_3D function zmean_fld_2D( fld ) result(fldzm) real(r8), intent(in) :: fld(pcols,begchunk:endchunk) real(r8) :: fldzm(pcols,begchunk:endchunk) - real(r8) :: Zonal_Bamp2d(nzmbas,pver) + real(r8) :: Zonal_Bamp2d(nzmbas) call ZMobj%calc_amps(fld,Zonal_Bamp2d) call ZMobj%eval_grid(Zonal_Bamp2d,fldzm) end function zmean_fld_2D From 567fa1d665a2909266a3ee774e725e97b30a7f05 Mon Sep 17 00:00:00 2001 From: daleihao Date: Wed, 1 May 2024 11:56:37 -0700 Subject: [PATCH 131/388] change top_rad rawdate to 1km --- .../bld/namelist_files/namelist_defaults.xml | 9 ++++++++ .../namelist_defaults_tools.xml | 6 +++--- .../tools/mksurfdata_map/src/mktopradMod.F90 | 21 ++++++++++++++----- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 8d7ad4fba90..0132320a215 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -1657,6 +1657,13 @@ this mask will have smb calculated over the entire global land surface lnd/clm2/mappingdata/maps/2.5x3.33/map_1km-merge-10min_HYDRO1K-merge-nomask_to_2.5x3.33_nomask_aave_da_c130405.nc + + +lnd/clm2/mappingdata/maps/0.25x0.25/map_0.01x0.01_nomask_to_0.25x0.25_nomask_aave_da_c240424.nc + + + @@ -1704,6 +1711,8 @@ this mask will have smb calculated over the entire global land surface >lnd/clm2/mappingdata/maps/0.5x0.5/map_360x720cru_cruncep_to_0.5x0.5_nomask_aave_da_c190417.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_1km-merge-10min_HYDRO1K-merge-nomask_to_0.5x0.5_nomask_aave_da_c190417.nc +lnd/clm2/mappingdata/maps/0.5x0.5/map_0.01x0.01_nomask_to_0.5x0.5_nomask_aave_da_c240424.nc diff --git a/components/elm/bld/namelist_files/namelist_defaults_tools.xml b/components/elm/bld/namelist_files/namelist_defaults_tools.xml index d948b16c95a..f97a41314be 100644 --- a/components/elm/bld/namelist_files/namelist_defaults_tools.xml +++ b/components/elm/bld/namelist_files/namelist_defaults_tools.xml @@ -177,7 +177,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 0.5x0.5 0.5x0.5 5x5min -0.1x0.1 +0.01x0.01 @@ -317,8 +317,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/rawdata/mksrf_fert.c220309.nc -lnd/clm2/rawdata/mksrf_toprad_0.1x0.1.c231218.nc +lnd/clm2/rawdata/mksrf_toprad_0.01x0.01.c240422.nc diff --git a/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 b/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 index e8ea66f9de4..0325019706f 100644 --- a/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 +++ b/components/elm/tools/mksurfdata_map/src/mktopradMod.F90 @@ -114,25 +114,36 @@ subroutine mktoprad(ldomain, mapfname, datfname, varname, ndiag, top_o, nodata) call check_ret(nf_get_var_double (ncidi, varid, top_i), subname) call check_ret(nf_close(ncidi), subname) - ! Read topo dataset + ! set mask as 0 when topo data is filled value: -9999 + allocate(mask_i(ns_i), stat=ier) + if (ier /= 0) then + write(6,*)'mktoprad allocation error'; call abort() + end if + + mask_i(:) = 1._r8 + do ni = 1,ns_i + if (top_i(ni) < -1000._r8) then + mask_i(ni) = 0._r8 + end if + enddo + + ! Read mapping file call gridmap_mapread(tgridmap, mapfname) ! Error checks for domain and map consistencies - ! Note that the topo dataset has no landmask - so a unit landmask is assumed - call domain_checksame( tdomain, ldomain, tgridmap ) ! Determine top_o on output grid - top_o(:) = nodata - call gridmap_areaave(tgridmap, top_i, top_o, nodata=nodata) + call gridmap_areaave(tgridmap, top_i, top_o, nodata=nodata, mask_src=mask_i) ! Deallocate dynamic memory call domain_clean(tdomain) call gridmap_clean(tgridmap) deallocate (top_i) + deallocate (mask_i) write (6,*) 'Successfully made topography parameters' write (6,*) From f2d82805a6a2151a82d7d716f49b25ac7fcb57b3 Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 28 Mar 2024 10:58:01 -0700 Subject: [PATCH 132/388] chg use_extrasnowlayers to 5 layers instead of 16 --- components/elm/src/biogeophys/SnowHydrologyMod.F90 | 9 ++++++--- components/elm/src/main/elm_varpar.F90 | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 6354dd598b0..897326d67fd 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -849,7 +849,8 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc(:) = dzmin(:) else - dzminloc16(:) = dzmin16(:) + dzminloc(:) = dzmin(:) + !dzminloc16(:) = dzmin16(:) endif ! Add lsadz to dzmin for lakes @@ -862,7 +863,8 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc(:) = dzmin(:) + lsadz else - dzminloc16(:) = dzmin16(:) + lsadz + dzminloc(:) = dzmin(:) + lsadz + !dzminloc16(:) = dzmin16(:) + lsadz end if end if end if @@ -1044,7 +1046,8 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc_mssi_c = dzminloc(mssi(c)) else - dzminloc_mssi_c = dzminloc16(mssi(c)) + dzminloc_mssi_c = dzminloc(mssi(c)) + !dzminloc_mssi_c = dzminloc16(mssi(c)) end if if ((frac_sno_eff(c)*dz(c,i) < dzminloc_mssi_c) .or. & ((h2osoi_ice(c,i) + h2osoi_liq(c,i))/(frac_sno_eff(c)*dz(c,i)) < 50._r8)) then diff --git a/components/elm/src/main/elm_varpar.F90 b/components/elm/src/main/elm_varpar.F90 index 21e8f659210..003b67e7b8a 100644 --- a/components/elm/src/main/elm_varpar.F90 +++ b/components/elm/src/main/elm_varpar.F90 @@ -204,7 +204,7 @@ subroutine elm_varpar_init() if (.not. use_extrasnowlayers) then nlevsno = 5 ! maximum number of snow layers else - nlevsno = 16 ! maximum number of snow layers (for firn model) + nlevsno = 5!16 ! maximum number of snow layers (for firn model) end if ! here is a switch to set the number of soil levels for the biogeochemistry calculations. From 107d8b9a79d65c9787190a2a0670a56ca3c36792 Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 11 Apr 2024 16:33:11 -0700 Subject: [PATCH 133/388] minor mods to use_extrasnowlayers5lyrs --- components/elm/src/main/elm_varcon.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/elm/src/main/elm_varcon.F90 b/components/elm/src/main/elm_varcon.F90 index 01df6ce0afd..69cd6f3f3fe 100644 --- a/components/elm/src/main/elm_varcon.F90 +++ b/components/elm/src/main/elm_varcon.F90 @@ -249,7 +249,8 @@ subroutine elm_varcon_init() allocate( dzsoifl(1:nlevsoifl )) if (use_extrasnowlayers) then - h2osno_max = 30000._r8 + h2osno_max = 1000._r8 + !h2osno_max = 30000._r8 end if end subroutine elm_varcon_init From a0cf3c8475ccabc3f0389a0335041e6c89aa42f7 Mon Sep 17 00:00:00 2001 From: Chloe Date: Fri, 26 Apr 2024 14:20:56 -0700 Subject: [PATCH 134/388] change use_extrasnowlayers to use_firn_percolation_and_compaction to run with improved snow physics in a 5 layer scheme --- .../namelist_files/namelist_definition.xml | 8 ++++++ components/elm/src/biogeophys/AerosolMod.F90 | 4 +-- .../elm/src/biogeophys/BalanceCheckMod.F90 | 6 ++--- .../elm/src/biogeophys/CanopyHydrologyMod.F90 | 12 ++++----- .../src/biogeophys/HydrologyNoDrainageMod.F90 | 4 +-- .../elm/src/biogeophys/LakeFluxesMod.F90 | 4 +-- .../elm/src/biogeophys/LakeHydrologyMod.F90 | 18 ++++++------- .../elm/src/biogeophys/SnowHydrologyMod.F90 | 25 ++++++++----------- .../elm/src/biogeophys/SnowSnicarMod.F90 | 6 ++--- .../elm/src/biogeophys/SoilFluxesMod.F90 | 4 +-- components/elm/src/main/controlMod.F90 | 5 +++- components/elm/src/main/elm_driver.F90 | 6 ++--- components/elm/src/main/elm_varcon.F90 | 4 +-- components/elm/src/main/elm_varctl.F90 | 1 + components/elm/src/main/elm_varpar.F90 | 2 +- 15 files changed, 59 insertions(+), 50 deletions(-) diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 0f8b03dfec3..933c9bcc0dc 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -709,6 +709,14 @@ snowpack conditions on glaciers and ice sheets, including a semi-empirical firn densification model. + +This option enables more realistic +snowpack conditions on glaciers and ice sheets, including a semi-empirical +firn densification model. uses the same physics as use_extrasnowlayers but +uses the original 5 snow layer scheme + + Toggle to turn all history output completely OFF (possibly used for testing) diff --git a/components/elm/src/biogeophys/AerosolMod.F90 b/components/elm/src/biogeophys/AerosolMod.F90 index d97c48dfd29..81fc8d62abc 100644 --- a/components/elm/src/biogeophys/AerosolMod.F90 +++ b/components/elm/src/biogeophys/AerosolMod.F90 @@ -5,7 +5,7 @@ module AerosolMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use elm_varpar , only : nlevsno - use elm_varctl , only : use_extrasnowlayers + use elm_varctl , only : use_firn_percolation_and_compaction use elm_time_manager , only : get_step_size use atm2lndType , only : atm2lnd_type use AerosolType , only : aerosol_type @@ -107,7 +107,7 @@ subroutine AerosolMasses(bounds, num_on, filter_on, num_off, filter_off, aerosol ! layer mass of snow: snowmass = h2osoi_ice(c,j) + h2osoi_liq(c,j) - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ! Correct the top layer aerosol mass to account for snow capping. ! This approach conserves the aerosol mass concentration ! (but not the aerosol amss) when snow-capping is invoked diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index 1280f7f9493..7737f2adbe3 100755 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -9,7 +9,7 @@ module BalanceCheckMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use abortutils , only : endrun - use elm_varctl , only : iulog, use_var_soil_thick, use_extrasnowlayers + use elm_varctl , only : iulog, use_var_soil_thick, use_firn_percolation_and_compaction use elm_varcon , only : namep, namec use GetGlobalValuesMod , only : GetGlobalIndex use atm2lndType , only : atm2lnd_type @@ -445,7 +445,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) + qflx_sl_top_soil(c) if (lun_pp%itype(l) == istdlak) then - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if ( do_capsnow(c)) then snow_sources(c) = qflx_snow_grnd_col(c) & + frac_sno_eff(c) * (qflx_dew_snow(c) + qflx_dew_grnd(c) ) @@ -473,7 +473,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & endif if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop .or. lun_pp%itype(l) == istwet ) then - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if (do_capsnow(c)) then snow_sources(c) = frac_sno_eff(c) * (qflx_dew_snow(c) + qflx_dew_grnd(c) ) & + qflx_h2osfc_to_ice(c) + qflx_prec_grnd(c) diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index 7726d03105e..5381b1358f8 100755 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -16,7 +16,7 @@ module CanopyHydrologyMod use shr_sys_mod , only : shr_sys_flush use decompMod , only : bounds_type use abortutils , only : endrun - use elm_varctl , only : iulog, tw_irr, extra_gw_irr, irrigate, use_extrasnowlayers + use elm_varctl , only : iulog, tw_irr, extra_gw_irr, irrigate, use_firn_percolation_and_compaction use LandunitType , only : lun_pp use atm2lndType , only : atm2lnd_type use AerosolType , only : aerosol_type @@ -433,7 +433,7 @@ subroutine CanopyHydrology(bounds, & qflx_prec_grnd(p) = qflx_prec_grnd_snow(p) + qflx_prec_grnd_rain(p) - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if (do_capsnow(c)) then qflx_snwcp_liq(p) = qflx_prec_grnd_rain(p) qflx_snwcp_ice(p) = qflx_prec_grnd_snow(p) @@ -491,7 +491,7 @@ subroutine CanopyHydrology(bounds, & ! Determine snow height and snow water - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then call NewSnowBulkDensity(bounds, num_nolakec, filter_nolakec, & top_as, bifall(bounds%begc:bounds%endc)) end if @@ -517,13 +517,13 @@ subroutine CanopyHydrology(bounds, & swe_old(c,j)=h2osoi_liq(c,j)+h2osoi_ice(c,j) enddo - if (do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then dz_snowf = 0._r8 newsnow(c) = qflx_snow_grnd_col(c) * dtime frac_sno(c)=1._r8 int_snow(c) = 5.e2_r8 else - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if (forc_t(t) > tfrz + 2._r8) then bifall(c)=50._r8 + 1.7_r8*(17.0_r8)**1.5_r8 else if (forc_t(t) > tfrz - 15._r8) then @@ -662,7 +662,7 @@ subroutine CanopyHydrology(bounds, & ! as the surface air temperature newnode = 0 ! flag for when snow node will be initialized - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if (snl(c) == 0 .and. qflx_snow_grnd_col(c) > 0.0_r8 .and. frac_sno(c)*snow_depth(c) >= 0.01_r8) then newnode = 1 snl(c) = -1 diff --git a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 index 56da904c522..fa6fe25c4ae 100644 --- a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -7,7 +7,7 @@ Module HydrologyNoDrainageMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use elm_varctl , only : iulog, use_vichydro, use_extrasnowlayers + use elm_varctl , only : iulog, use_vichydro, use_extrasnowlayers, use_firn_percolation_and_compaction use elm_varcon , only : e_ice, denh2o, denice, rpi, spval use atm2lndType , only : atm2lnd_type use lnd2atmType , only : lnd2atm_type @@ -300,7 +300,7 @@ subroutine HydrologyNoDrainage(bounds, & endif #endif - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then call SnowCapping(bounds, num_nolakec, filter_nolakec, num_snowc, filter_snowc, & aerosol_vars) end if diff --git a/components/elm/src/biogeophys/LakeFluxesMod.F90 b/components/elm/src/biogeophys/LakeFluxesMod.F90 index d149e4c9911..92733834c77 100644 --- a/components/elm/src/biogeophys/LakeFluxesMod.F90 +++ b/components/elm/src/biogeophys/LakeFluxesMod.F90 @@ -52,7 +52,7 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, use elm_varpar , only : nlevlak use elm_varcon , only : hvap, hsub, hfus, cpair, cpliq, tkwat, tkice, tkair use elm_varcon , only : sb, vkc, grav, denh2o, tfrz, spval, zsno - use elm_varctl , only : iulog, use_lch4, use_extrasnowlayers + use elm_varctl , only : iulog, use_lch4, use_firn_percolation_and_compaction use LakeCon , only : betavis, z0frzlake, tdmax, emg_lake use LakeCon , only : lake_use_old_fcrit_minz0 use LakeCon , only : minz0lake, cur0, cus, curm, fcrit @@ -695,7 +695,7 @@ subroutine LakeFluxes(bounds, num_lakec, filter_lakec, num_lakep, filter_lakep, qflx_dirct_rain(p) = 0._r8 qflx_leafdrip(p) = 0._r8 - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ! Because they will be used in pft2col initialize here. ! This will be overwritten in LakeHydrology qflx_snwcp_ice(p) = 0._r8 diff --git a/components/elm/src/biogeophys/LakeHydrologyMod.F90 b/components/elm/src/biogeophys/LakeHydrologyMod.F90 index 7391a2d80fb..f0bf1d373fc 100644 --- a/components/elm/src/biogeophys/LakeHydrologyMod.F90 +++ b/components/elm/src/biogeophys/LakeHydrologyMod.F90 @@ -74,7 +74,7 @@ subroutine LakeHydrology(bounds, & !$acc routine seq use elm_varcon , only : denh2o, denice, spval, hfus, tfrz, cpliq, cpice use elm_varpar , only : nlevsno, nlevgrnd, nlevsoi - use elm_varctl , only : iulog, use_extrasnowlayers, use_lake_wat_storage + use elm_varctl , only : iulog, use_extrasnowlayers, use_lake_wat_storage, use_firn_percolation_and_compaction use elm_time_manager, only : get_step_size use SnowHydrologyMod, only : SnowCompaction, CombineSnowLayers, SnowWater, BuildSnowFilter use SnowHydrologyMod, only : DivideSnowLayers, DivideExtraSnowLayers, SnowCapping @@ -256,7 +256,7 @@ subroutine LakeHydrology(bounds, & qflx_dirct_rain(p) = 0._r8 qflx_leafdrip(p) = 0._r8 - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then if (do_capsnow(c)) then qflx_snwcp_ice(p) = qflx_prec_grnd_snow(p) qflx_snwcp_liq(p) = qflx_prec_grnd_rain(p) @@ -288,7 +288,7 @@ subroutine LakeHydrology(bounds, & ! U.S.Department of Agriculture Forest Service, Project F, ! Progress Rep. 1, Alta Avalanche Study Center:Snow Layer Densification. - if (do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then dz_snowf = 0._r8 else if (forc_t(t) > tfrz + 2._r8) then @@ -400,7 +400,7 @@ subroutine LakeHydrology(bounds, & ! Update the pft-level qflx_snowcap ! This was moved in from Hydrology2 to keep all pft-level ! calculations out of Hydrology2 - if (do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then qflx_snwcp_ice(p) = qflx_snwcp_ice(p) + qflx_dew_snow(p) qflx_snwcp_liq(p) = qflx_snwcp_liq(p) + qflx_dew_grnd(p) end if @@ -422,7 +422,7 @@ subroutine LakeHydrology(bounds, & ! Update snow pack for dew & sub. h2osno_temp = h2osno(c) - if (do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then h2osno(c) = h2osno(c) - qflx_sub_snow(p)*dtime qflx_snwcp_ice(p) = qflx_snwcp_ice(p) + qflx_dew_snow(p) qflx_snwcp_liq(p) = qflx_snwcp_liq(p) + qflx_dew_grnd(p) @@ -437,7 +437,7 @@ subroutine LakeHydrology(bounds, & end if end if - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then qflx_snwcp_ice_col(c) = qflx_snwcp_ice(p) qflx_snwcp_liq_col(c) = qflx_snwcp_liq(p) end if @@ -485,7 +485,7 @@ subroutine LakeHydrology(bounds, & num_shlakesnowc, filter_shlakesnowc, num_shlakenosnowc, filter_shlakenosnowc, & atm2lnd_vars, aerosol_vars) - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then call SnowCapping(bounds, num_lakec, filter_lakec, num_shlakesnowc, filter_shlakesnowc, & aerosol_vars) end if @@ -719,7 +719,7 @@ subroutine LakeHydrology(bounds, & if (use_lake_wat_storage) then qflx_qrgwl(c) = 0._r8 if (wslake(c) >= 5000._r8) then - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then qflx_snwcp = qflx_snwcp_ice(p) else qflx_snwcp = qflx_snwcp_ice_col(c) @@ -732,7 +732,7 @@ subroutine LakeHydrology(bounds, & (endwb(c) - begwb(c)) endwb(c) = endwb(c) + wslake(c) else - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then qflx_snwcp = qflx_snwcp_ice(p) else qflx_snwcp = qflx_snwcp_ice_col(c) diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 897326d67fd..f9270289d05 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -18,7 +18,7 @@ module SnowHydrologyMod use decompMod , only : bounds_type use abortutils , only : endrun use elm_varpar , only : nlevsno - use elm_varctl , only : iulog, use_extrasnowlayers + use elm_varctl , only : iulog, use_extrasnowlayers, use_firn_percolation_and_compaction use elm_varcon , only : namec, h2osno_max use atm2lndType , only : atm2lnd_type use AerosolType , only : aerosol_type @@ -233,7 +233,7 @@ subroutine SnowWater(bounds, & c = filter_snowc(fc) l=col_pp%landunit(c) - if (do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then wgdif = h2osoi_ice(c,snl(c)+1) - frac_sno_eff(c)*qflx_sub_snow(c)*dtime h2osoi_ice(c,snl(c)+1) = wgdif if (wgdif < 0._r8) then @@ -623,7 +623,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! Begin calculation - note that the following column loops are only invoked if snl(c) < 0 - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then do fc = 1, num_snowc c = filter_snowc(fc) burden(c) = 0._r8 @@ -637,7 +637,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & do j = -nlevsno+1, 0 do fc = 1, num_snowc c = filter_snowc(fc) - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then t = col_pp%topounit(c) end if if (j >= snl(c)+1) then @@ -647,7 +647,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! If void is negative, then increase dz such that void = 0. ! This should be done for any landunit, but for now is done only for glacier_mec 1andunits. - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ! I don't think the next 5 lines are necessary (removed in CLMv5) l = col_pp%landunit(c) if (ltype(l)==istice_mec .and. void < 0._r8) then @@ -665,7 +665,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & dexpf = exp(-c4*td) ! Settling as a result of destructive metamorphism - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ddz1 = -c3*dexpf if (bi > dm) ddz1 = ddz1*exp(-46.0e-3_r8*(bi-dm)) else @@ -685,7 +685,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & if (h2osoi_liq(c,j) > 0.01_r8*dz(c,j)*frac_sno(c)) ddz1=ddz1*c5 ! Compaction due to overburden - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ddz2 = -(burden(c)+wx/2._r8)*exp(-0.08_r8*td - c2*bi)/eta0 else p_gls = max(denice / bi, 1._r8) * grav * (burden(c) + wx/2._r8) @@ -724,7 +724,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ddz3 = 0._r8 end if - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then ! Compaction occurring due to wind drift call WindDriftCompaction( & bi = bi, & @@ -849,8 +849,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc(:) = dzmin(:) else - dzminloc(:) = dzmin(:) - !dzminloc16(:) = dzmin16(:) + dzminloc16(:) = dzmin16(:) endif ! Add lsadz to dzmin for lakes @@ -863,8 +862,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc(:) = dzmin(:) + lsadz else - dzminloc(:) = dzmin(:) + lsadz - !dzminloc16(:) = dzmin16(:) + lsadz + dzminloc16(:) = dzmin16(:) + lsadz end if end if end if @@ -1046,8 +1044,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (.not. use_extrasnowlayers) then dzminloc_mssi_c = dzminloc(mssi(c)) else - dzminloc_mssi_c = dzminloc(mssi(c)) - !dzminloc_mssi_c = dzminloc16(mssi(c)) + dzminloc_mssi_c = dzminloc16(mssi(c)) end if if ((frac_sno_eff(c)*dz(c,i) < dzminloc_mssi_c) .or. & ((h2osoi_ice(c,i) + h2osoi_liq(c,i))/(frac_sno_eff(c)*dz(c,i)) < 50._r8)) then diff --git a/components/elm/src/biogeophys/SnowSnicarMod.F90 b/components/elm/src/biogeophys/SnowSnicarMod.F90 index d6d6de75ffa..de161c1d4c9 100644 --- a/components/elm/src/biogeophys/SnowSnicarMod.F90 +++ b/components/elm/src/biogeophys/SnowSnicarMod.F90 @@ -11,7 +11,7 @@ module SnowSnicarMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_sys_mod , only : shr_sys_flush use shr_log_mod , only : errMsg => shr_log_errMsg - use elm_varctl , only : iulog, use_extrasnowlayers + use elm_varctl , only : iulog, use_firn_percolation_and_compaction use elm_varcon , only : namec use shr_const_mod , only : SHR_CONST_RHOICE use abortutils , only : endrun @@ -1435,13 +1435,13 @@ subroutine SnowAge_grain(bounds, & ! RE-FREEZING ! ! new snowfall [kg/m2] - if (do_capsnow(c_idx) .and. .not. use_extrasnowlayers) then + if (do_capsnow(c_idx) .and. .not. use_firn_percolation_and_compaction) then newsnow = max(0._r8, (qflx_snwcp_ice(c_idx)*dtime)) else newsnow = max(0._r8, (qflx_snow_grnd_col(c_idx)*dtime)) endif - if (use_extrasnowlayers) then + if (use_firn_percolation_and_compaction) then snw_rds_refrz = 1500._r8 else snw_rds_refrz = 1000._r8 diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index c76d22d5c99..1b221a617a8 100644 --- a/components/elm/src/biogeophys/SoilFluxesMod.F90 +++ b/components/elm/src/biogeophys/SoilFluxesMod.F90 @@ -8,7 +8,7 @@ module SoilFluxesMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use abortutils , only : endrun - use elm_varctl , only : iulog, use_extrasnowlayers + use elm_varctl , only : iulog, use_firn_percolation_and_compaction use perfMod_GPU use elm_varpar , only : nlevsno, nlevgrnd, nlevurb, max_patch_per_col use atm2lndType , only : atm2lnd_type @@ -349,7 +349,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & ! This was moved in from Hydrology2 to keep all pft-level ! calculations out of Hydrology2 - if (col_pp%snl(c) < 0 .and. do_capsnow(c) .and. .not. use_extrasnowlayers) then + if (col_pp%snl(c) < 0 .and. do_capsnow(c) .and. .not. use_firn_percolation_and_compaction) then qflx_snwcp_liq(p) = qflx_snwcp_liq(p)+frac_sno_eff(c)*qflx_dew_grnd(p) qflx_snwcp_ice(p) = qflx_snwcp_ice(p)+frac_sno_eff(c)*qflx_dew_snow(p) end if diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 3b8c08be31b..078ced1064c 100755 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -280,7 +280,8 @@ subroutine control_init( ) namelist /elm_inparm/ & use_nofire, use_lch4, use_vertsoilc, use_extralakelayers, & use_vichydro, use_century_decomp, use_cn, use_crop, use_snicar_frc, & - use_snicar_ad, use_extrasnowlayers, use_vancouver, use_mexicocity, use_noio + use_snicar_ad, use_firn_percolation_and_compaction, use_extrasnowlayers,& + use_vancouver, use_mexicocity, use_noio ! cpl_bypass variables namelist /elm_inparm/ metdata_type, metdata_bypass, metdata_biases, & @@ -721,6 +722,7 @@ subroutine control_spmd() call mpi_bcast (use_vertsoilc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_extralakelayers, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_extrasnowlayers, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_firn_percolation_and_compaction, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_vichydro, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_century_decomp, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_cn, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -1020,6 +1022,7 @@ subroutine control_print () write(iulog,*) ' use_lake_wat_storage = ', use_lake_wat_storage write(iulog,*) ' use_extralakelayers = ', use_extralakelayers write(iulog,*) ' use_extrasnowlayers = ', use_extrasnowlayers + write(iulog,*) ' use_firn_percolation_and_compaction = ', use_firn_percolation_and_compaction write(iulog,*) ' use_vichydro = ', use_vichydro write(iulog,*) ' use_century_decomp = ', use_century_decomp write(iulog,*) ' use_cn = ', use_cn diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index f385004a172..51f08bf235c 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -12,7 +12,7 @@ module elm_driver use shr_sys_mod , only : shr_sys_flush use shr_log_mod , only : errMsg => shr_log_errMsg use elm_varpar , only : nlevtrc_soil, nlevsoi - use elm_varctl , only : wrtdia, iulog, create_glacier_mec_landunit, use_fates, use_betr, use_extrasnowlayers + use elm_varctl , only : wrtdia, iulog, create_glacier_mec_landunit, use_fates, use_betr, use_firn_percolation_and_compaction use elm_varctl , only : use_cn, use_lch4, use_voc, use_noio, use_c13, use_c14 use elm_varctl , only : use_erosion, use_fates_sp, use_fan use elm_varctl , only : mpi_sync_nstep_freq @@ -1622,7 +1622,7 @@ subroutine elm_drv_init(bounds, & ! Save snow mass at previous time step h2osno_old(c) = h2osno(c) - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then ! Decide whether to cap snow if (h2osno(c) > h2osno_max) then do_capsnow(c) = .true. @@ -1790,7 +1790,7 @@ subroutine elm_drv_patch2col (bounds, num_nolakec, filter_nolakec, & qflx_snow_grnd_patch(bounds%begp:bounds%endp), & qflx_snow_grnd_col (bounds%begc:bounds%endc)) - if (.not. use_extrasnowlayers) then + if (.not. use_firn_percolation_and_compaction) then call p2c (bounds, num_allc, filter_allc, & veg_wf%qflx_snwcp_liq(bounds%begp:bounds%endp), & col_wf%qflx_snwcp_liq(bounds%begc:bounds%endc)) diff --git a/components/elm/src/main/elm_varcon.F90 b/components/elm/src/main/elm_varcon.F90 index 69cd6f3f3fe..f2de019670c 100644 --- a/components/elm/src/main/elm_varcon.F90 +++ b/components/elm/src/main/elm_varcon.F90 @@ -249,8 +249,8 @@ subroutine elm_varcon_init() allocate( dzsoifl(1:nlevsoifl )) if (use_extrasnowlayers) then - h2osno_max = 1000._r8 - !h2osno_max = 30000._r8 + !h2osno_max = 1000._r8 + h2osno_max = 30000._r8 end if end subroutine elm_varcon_init diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index d5a61da8fdb..b61e63f93d6 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -359,6 +359,7 @@ module elm_varctl logical, public :: use_snicar_frc = .false. logical, public :: use_snicar_ad = .false. logical, public :: use_extrasnowlayers = .false. + logical, public :: use_firn_percolation_and_compaction = .false. logical, public :: use_vancouver = .false. logical, public :: use_mexicocity = .false. logical, public :: use_noio = .false. diff --git a/components/elm/src/main/elm_varpar.F90 b/components/elm/src/main/elm_varpar.F90 index 003b67e7b8a..21e8f659210 100644 --- a/components/elm/src/main/elm_varpar.F90 +++ b/components/elm/src/main/elm_varpar.F90 @@ -204,7 +204,7 @@ subroutine elm_varpar_init() if (.not. use_extrasnowlayers) then nlevsno = 5 ! maximum number of snow layers else - nlevsno = 5!16 ! maximum number of snow layers (for firn model) + nlevsno = 16 ! maximum number of snow layers (for firn model) end if ! here is a switch to set the number of soil levels for the biogeochemistry calculations. From 7c443fde301b0ba9eff6dffe61c980dfb8e1e6d3 Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 07:11:11 -0800 Subject: [PATCH 135/388] added ERA5 hourly & 6 hourly datm options --- .../datm/cime_config/config_component.xml | 10 +- .../cime_config/namelist_definition_datm.xml | 169 +++++++++++++++++- 2 files changed, 175 insertions(+), 4 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 94b0eab610d..73146daba5a 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -10,12 +10,14 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set GSWP3v1 data set + Fifth generation ECMWF reanalysis + Fifth generation ECMWF reanalysis,6 hourly data MOSART test data set using older NLDAS data NLDAS2 regional 0.125 degree data set over the U.S. (25-53N, 235-293E). WARNING: Garbage data will be produced for runs extending beyond this regional domain. Coupler hist data set (in this mode, it is strongly recommended that the model domain and the coupler history forcing are on the same domain) @@ -43,13 +45,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -68,6 +70,8 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEP CLMCRUNCEPv7 CLMGSWP3v1 + ERA5 + ERA5_6HR CLMMOSARTTEST CLMNLDAS2 CLM1PT diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 10d7111d433..a7b52113247 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -36,6 +36,8 @@ CLMCRUNCEP = Run with the CLM CRU NCEP V4 ( default ) forcing valid from 1900 to 2010 (force CLM) CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) + ERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -103,6 +105,26 @@ CLMGSWP3v1.Solar CLMGSWP3v1.Precip CLMGSWP3v1.TPQW + + ERA5.msdrswrf # mean surface direct shortwave radiation flux + ERA5.msdfswrf # mean surface diffuse shortwave radiation flux + ERA5.mcpr # mean convective precipitation rate + ERA5.mlspr # mean large-scale precipitation rate + ERA5.t2m # temperature at 2 m + ERA5.sp # surface pressure + ERA5.d2m # dew point temperature at 2 m + ERA5.w10 # wind speed at 10 m + ERA5.msdwlwrf # mean surface downward longwave radiation flux + + ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux + ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux + ERA5_6HR.mcpr # mean convective precipitation rate + ERA5_6HR.mlspr # mean large-scale precipitation rate + ERA5_6HR.t2m # temperature at 2 m + ERA5_6HR.sp # surface pressure + ERA5_6HR.d2m # dew point temperature at 2 m + ERA5_6HR.w10 # wind speed at 10 m + ERA5_6HR.msdwlwrf # mean surface downward longwave radiation flux CLMMOSARTTEST @@ -202,6 +224,8 @@ CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW + ERA5.msdrswrf,ERA5.msdfswrf,ERA5.mcpr,ERA5.mlspr, ERA5.t2m,ERA5.sp,ERA5.d2m,ERA5.w10,ERA5.msdwlwrf + ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW CORE2_NYF.GISS,CORE2_NYF.GXGXS,CORE2_NYF.NCEP @@ -234,6 +258,8 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 @@ -302,6 +328,8 @@ domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc nyf.giss.T62.051007.nc @@ -478,6 +506,24 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL3Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT/atm/datm7/NLDAS $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Solar $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Precip @@ -553,6 +599,24 @@ clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc clmforc.nldas.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Solr.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Prec.%ym.nc @@ -1523,6 +1587,60 @@ PSRF pbot FLDS lwdn + + msdrswrf swdndr + + + msdfswrf swdndf + + + mcpr precc + + + mlspr precl + + + t2m tbot + + + sp pbot + + + d2m tdew + + + w10 wind + + + msdwlwrf lwdn + + + msdrswrf swdndr + + + msdfswrf swdndf + + + mcpr precc + + + mlspr precl + + + t2m tbot + + + sp pbot + + + d2m tdew + + + w10 wind + + + msdwlwrf lwdn + TBOT tbot WIND wind @@ -1793,6 +1911,8 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN 1 @@ -1843,6 +1963,8 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START 1 @@ -1914,6 +2036,8 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END 1 @@ -1988,6 +2112,16 @@ 900 0 0 + -3600 + -3600 + -60 + -60 + -60 + -21600 + -21600 + -60 + -60 + -60 @@ -2054,6 +2188,8 @@ NULL CLMNCEP + CLMNCEP + CLMNCEP CORE2_NYF CORE2_IAF CORE_IAF_JRA @@ -2093,7 +2229,9 @@ valid values: 'copy','spval','nn','nnoni','nnonj' - nn + nn + copy + copy @@ -2248,6 +2386,16 @@ nearest coszen nearest + coszen + coszen + upper + linear + linear + coszen + coszen + upper + upper + upper coszen nearest nearest @@ -2340,6 +2488,25 @@ 3.0 3.0 3.0 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + From 015e00321c3da53335643ceee01ce5043ec01b84 Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 12:24:20 -0800 Subject: [PATCH 136/388] added ERA5 datm, not functional due to land ice error --- .../datm/cime_config/config_component.xml | 6 +- .../cime_config/namelist_definition_datm.xml | 130 +++++++++--------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 73146daba5a..6d10109075b 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -45,13 +45,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ELMERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -70,7 +70,7 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEP CLMCRUNCEPv7 CLMGSWP3v1 - ERA5 + ELMERA5 ERA5_6HR CLMMOSARTTEST CLMNLDAS2 diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index a7b52113247..2696126a8a5 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -36,8 +36,8 @@ CLMCRUNCEP = Run with the CLM CRU NCEP V4 ( default ) forcing valid from 1900 to 2010 (force CLM) CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) - ERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present - ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ELMERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -106,15 +106,15 @@ CLMGSWP3v1.Precip CLMGSWP3v1.TPQW - ERA5.msdrswrf # mean surface direct shortwave radiation flux - ERA5.msdfswrf # mean surface diffuse shortwave radiation flux - ERA5.mcpr # mean convective precipitation rate - ERA5.mlspr # mean large-scale precipitation rate - ERA5.t2m # temperature at 2 m - ERA5.sp # surface pressure - ERA5.d2m # dew point temperature at 2 m - ERA5.w10 # wind speed at 10 m - ERA5.msdwlwrf # mean surface downward longwave radiation flux + ELMERA5.msdrswrf # mean surface direct shortwave radiation flux + ELMERA5.msdfswrf # mean surface diffuse shortwave radiation flux + ELMERA5.mcpr # mean convective precipitation rate + ELMERA5.mlspr # mean large-scale precipitation rate + ELMERA5.t2m # temperature at 2 m + ELMERA5.sp # surface pressure + ELMERA5.d2m # dew point temperature at 2 m + ELMERA5.w10 # wind speed at 10 m + ELMERA5.msdwlwrf # mean surface downward longwave radiation flux ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux @@ -224,7 +224,7 @@ CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW - ERA5.msdrswrf,ERA5.msdfswrf,ERA5.mcpr,ERA5.mlspr, ERA5.t2m,ERA5.sp,ERA5.d2m,ERA5.w10,ERA5.msdwlwrf + ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW @@ -258,7 +258,7 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 @@ -328,7 +328,7 @@ domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc - domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc @@ -506,15 +506,15 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL3Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec @@ -599,15 +599,15 @@ clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc - elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc - elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc - elmforc.ERA5.c2018.0.25d.t2m.%ym.nc - elmforc.ERA5.c2018.0.25d.sp.%ym.nc - elmforc.ERA5.c2018.0.25d.d2m.%ym.nc - elmforc.ERA5.c2018.0.25d.w10.%ym.nc - elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc @@ -1587,31 +1587,31 @@ PSRF pbot FLDS lwdn - + msdrswrf swdndr - + msdfswrf swdndf - + mcpr precc - + mlspr precl - + t2m tbot - + sp pbot - + d2m tdew - + w10 wind - + msdwlwrf lwdn @@ -1911,7 +1911,7 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN @@ -1963,7 +1963,7 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START @@ -2036,7 +2036,7 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END @@ -2112,11 +2112,11 @@ 900 0 0 - -3600 - -3600 - -60 - -60 - -60 + -3600 + -3600 + -60 + -60 + -60 -21600 -21600 -60 @@ -2188,7 +2188,7 @@ NULL CLMNCEP - CLMNCEP + CLMNCEP CLMNCEP CORE2_NYF CORE2_IAF @@ -2230,7 +2230,7 @@ nn - copy + copy copy @@ -2386,11 +2386,11 @@ nearest coszen nearest - coszen - coszen - upper - linear - linear + coszen + coszen + upper + linear + linear coszen coszen upper @@ -2488,15 +2488,15 @@ 3.0 3.0 3.0 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 2.5 2.5 2.5 From dc935c888cbb3687a7f9879f278fe9a36e05655e Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 17:39:51 -0800 Subject: [PATCH 137/388] ERA% datm debugging --- .../datm/cime_config/config_component.xml | 2 ++ .../cime_config/namelist_definition_datm.xml | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 6d10109075b..b8fbcc930c5 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -15,6 +15,7 @@ QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set + CRUJRA data set GSWP3v1 data set Fifth generation ECMWF reanalysis Fifth generation ECMWF reanalysis,6 hourly data @@ -65,6 +66,7 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CORE_RYF8485_JRA CORE_RYF9091_JRA CORE_RYF0304_JRA + CRUJRA CLM_QIAN CLM_QIAN_WISO CLMCRUNCEP diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 2696126a8a5..8deec7e1946 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -223,6 +223,7 @@ CLM1PT.$ATM_GRID CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW + CRUJRA.Solar,CRUJRA.Precip,CRUJRA.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf @@ -256,6 +257,7 @@ null $DIN_LOC_ROOT/atm/datm7 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 @@ -325,6 +327,7 @@ domain.T62.050609.nc domain.T62.050609.nc domain.lnd.360x720_cruncep.130305.nc + domain.crujra.0.5x0.5.c200728.nc domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc @@ -497,6 +500,9 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Solar6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Precip6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/TPHWL6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Solar6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Precip6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/TPHWL6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL @@ -596,6 +602,9 @@ clmforc.cruncep.V7.c2016.0.5d.Solr.%ym.nc clmforc.cruncep.V7.c2016.0.5d.Prec.%ym.nc clmforc.cruncep.V7.c2016.0.5d.TPQWL.%ym.nc + clmforc.CRUJRA.0.5d.Solr.%ym.nc + clmforc.CRUJRA.0.5d.Prec.%ym.nc + clmforc.CRUJRA.0.5d.TPQWL.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc @@ -1574,6 +1583,18 @@ QBOT shum PSRF pbot + + FSDS swdn + + + PRECTmms precn + + + TBOT tbot + WIND wind + QBOT shum + PSRF pbot + FSDS swdn @@ -1915,6 +1936,7 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN 1 1 1 @@ -1967,6 +1989,7 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START 1 2010 2010 @@ -2040,6 +2063,7 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END 1 2011 2011 @@ -2137,7 +2161,7 @@ char streams shr_strdata_nml - CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,NULL + CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,CRUJRA,NULL general method that operates on the data. this is generally implemented in the data models but is set in the strdata method for @@ -2198,6 +2222,7 @@ COPYALL COPYALL COPYALL + CRUJRA @@ -2384,6 +2409,8 @@ nearest coszen nearest + coszen + nearest coszen nearest coszen From 26fe710f8342eda7a5ff18586e64e5013bc53dbe Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 8 Feb 2024 11:19:58 -0800 Subject: [PATCH 138/388] small datm & mcmodel changes ; ERA5 still too slow --- cime_config/machines/cmake_macros/intel_pm-cpu.cmake | 2 +- .../data_comps/datm/cime_config/namelist_definition_datm.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake index 0eab406627a..8eae9542d63 100644 --- a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake +++ b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake @@ -21,7 +21,7 @@ if (compile_threaded) endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS " -fp-model=precise") # and manually add precise +string(APPEND CMAKE_CXX_FLAGS "-mcmodel=medium -dynamic -fp-model=precise") # and manually add precise #message(STATUS "ndk CXXFLAGS=${CXXFLAGS}") string(APPEND CMAKE_Fortran_FLAGS " -fp-model=consistent -fimf-use-svml") diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 8deec7e1946..8d774503033 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -2421,8 +2421,8 @@ coszen coszen upper - upper - upper + linear + linear coszen nearest nearest From 3389d07a3ae5fa3f73e174a6b30eff0be92f1e0b Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 8 Feb 2024 17:29:07 -0800 Subject: [PATCH 139/388] functional ERA5 datm --- .../machines/cmake_macros/intel_pm-cpu.cmake | 2 +- .../datm/cime_config/config_component.xml | 4 +-- .../cime_config/namelist_definition_datm.xml | 29 +------------------ 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake index 8eae9542d63..0eab406627a 100644 --- a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake +++ b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake @@ -21,7 +21,7 @@ if (compile_threaded) endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS "-mcmodel=medium -dynamic -fp-model=precise") # and manually add precise +string(APPEND CMAKE_CXX_FLAGS " -fp-model=precise") # and manually add precise #message(STATUS "ndk CXXFLAGS=${CXXFLAGS}") string(APPEND CMAKE_Fortran_FLAGS " -fp-model=consistent -fimf-use-svml") diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index b8fbcc930c5..5a2fa9c927e 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -15,7 +15,6 @@ QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set - CRUJRA data set GSWP3v1 data set Fifth generation ECMWF reanalysis Fifth generation ECMWF reanalysis,6 hourly data @@ -46,7 +45,7 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml @@ -66,7 +65,6 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CORE_RYF8485_JRA CORE_RYF9091_JRA CORE_RYF0304_JRA - CRUJRA CLM_QIAN CLM_QIAN_WISO CLMCRUNCEP diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 8d774503033..0f7684f0072 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -223,7 +223,6 @@ CLM1PT.$ATM_GRID CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW - CRUJRA.Solar,CRUJRA.Precip,CRUJRA.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf @@ -257,7 +256,6 @@ null $DIN_LOC_ROOT/atm/datm7 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 @@ -327,7 +325,6 @@ domain.T62.050609.nc domain.T62.050609.nc domain.lnd.360x720_cruncep.130305.nc - domain.crujra.0.5x0.5.c200728.nc domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc @@ -500,9 +497,6 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Solar6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Precip6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/TPHWL6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Solar6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Precip6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/TPHWL6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL @@ -602,9 +596,6 @@ clmforc.cruncep.V7.c2016.0.5d.Solr.%ym.nc clmforc.cruncep.V7.c2016.0.5d.Prec.%ym.nc clmforc.cruncep.V7.c2016.0.5d.TPQWL.%ym.nc - clmforc.CRUJRA.0.5d.Solr.%ym.nc - clmforc.CRUJRA.0.5d.Prec.%ym.nc - clmforc.CRUJRA.0.5d.TPQWL.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc @@ -1583,18 +1574,6 @@ QBOT shum PSRF pbot - - FSDS swdn - - - PRECTmms precn - - - TBOT tbot - WIND wind - QBOT shum - PSRF pbot - FSDS swdn @@ -1936,7 +1915,6 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN 1 1 1 @@ -1989,7 +1967,6 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START 1 2010 2010 @@ -2063,7 +2040,6 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END 1 2011 2011 @@ -2161,7 +2137,7 @@ char streams shr_strdata_nml - CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,CRUJRA,NULL + CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,NULL general method that operates on the data. this is generally implemented in the data models but is set in the strdata method for @@ -2222,7 +2198,6 @@ COPYALL COPYALL COPYALL - CRUJRA @@ -2409,8 +2384,6 @@ nearest coszen nearest - coszen - nearest coszen nearest coszen From 3840bd75be22c4a08f7c300be0c1628afbad6e2f Mon Sep 17 00:00:00 2001 From: Chloe Date: Fri, 26 Apr 2024 15:00:01 -0700 Subject: [PATCH 140/388] Revert "Merge branch 'cwhicker_m20240206_2_datm-era5_modBG25' into cwhicker/elm/use_extrasnowlayers-5lyrs/1_ERA5" This reverts commit 3d35017ffb2388120ed0c34b7061e0abccc8c88b, reversing changes made to b29ce48444e433697343bd60caab6262096aa2b4. merged wrong branch --- .../datm/cime_config/config_component.xml | 10 +- .../cime_config/namelist_definition_datm.xml | 169 +----------------- 2 files changed, 4 insertions(+), 175 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 5a2fa9c927e..94b0eab610d 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -10,14 +10,12 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set GSWP3v1 data set - Fifth generation ECMWF reanalysis - Fifth generation ECMWF reanalysis,6 hourly data MOSART test data set using older NLDAS data NLDAS2 regional 0.125 degree data set over the U.S. (25-53N, 235-293E). WARNING: Garbage data will be produced for runs extending beyond this regional domain. Coupler hist data set (in this mode, it is strongly recommended that the model domain and the coupler history forcing are on the same domain) @@ -45,13 +43,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ELMERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -70,8 +68,6 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEP CLMCRUNCEPv7 CLMGSWP3v1 - ELMERA5 - ERA5_6HR CLMMOSARTTEST CLMNLDAS2 CLM1PT diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 0f7684f0072..10d7111d433 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -36,8 +36,6 @@ CLMCRUNCEP = Run with the CLM CRU NCEP V4 ( default ) forcing valid from 1900 to 2010 (force CLM) CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) - ELMERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present - ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -105,26 +103,6 @@ CLMGSWP3v1.Solar CLMGSWP3v1.Precip CLMGSWP3v1.TPQW - - ELMERA5.msdrswrf # mean surface direct shortwave radiation flux - ELMERA5.msdfswrf # mean surface diffuse shortwave radiation flux - ELMERA5.mcpr # mean convective precipitation rate - ELMERA5.mlspr # mean large-scale precipitation rate - ELMERA5.t2m # temperature at 2 m - ELMERA5.sp # surface pressure - ELMERA5.d2m # dew point temperature at 2 m - ELMERA5.w10 # wind speed at 10 m - ELMERA5.msdwlwrf # mean surface downward longwave radiation flux - - ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux - ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux - ERA5_6HR.mcpr # mean convective precipitation rate - ERA5_6HR.mlspr # mean large-scale precipitation rate - ERA5_6HR.t2m # temperature at 2 m - ERA5_6HR.sp # surface pressure - ERA5_6HR.d2m # dew point temperature at 2 m - ERA5_6HR.w10 # wind speed at 10 m - ERA5_6HR.msdwlwrf # mean surface downward longwave radiation flux CLMMOSARTTEST @@ -224,8 +202,6 @@ CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW - ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf - ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW CORE2_NYF.GISS,CORE2_NYF.GXGXS,CORE2_NYF.NCEP @@ -258,8 +234,6 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 @@ -328,8 +302,6 @@ domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc - domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc - domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc nyf.giss.T62.051007.nc @@ -506,24 +478,6 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL3Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT/atm/datm7/NLDAS $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Solar $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Precip @@ -599,24 +553,6 @@ clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc - elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc - elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc - elmforc.ERA5.c2018.0.25d.t2m.%ym.nc - elmforc.ERA5.c2018.0.25d.sp.%ym.nc - elmforc.ERA5.c2018.0.25d.d2m.%ym.nc - elmforc.ERA5.c2018.0.25d.w10.%ym.nc - elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc - elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc - elmforc.ERA5.c2018.0.25d.t2m.%ym.nc - elmforc.ERA5.c2018.0.25d.sp.%ym.nc - elmforc.ERA5.c2018.0.25d.d2m.%ym.nc - elmforc.ERA5.c2018.0.25d.w10.%ym.nc - elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc clmforc.nldas.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Solr.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Prec.%ym.nc @@ -1587,60 +1523,6 @@ PSRF pbot FLDS lwdn - - msdrswrf swdndr - - - msdfswrf swdndf - - - mcpr precc - - - mlspr precl - - - t2m tbot - - - sp pbot - - - d2m tdew - - - w10 wind - - - msdwlwrf lwdn - - - msdrswrf swdndr - - - msdfswrf swdndf - - - mcpr precc - - - mlspr precl - - - t2m tbot - - - sp pbot - - - d2m tdew - - - w10 wind - - - msdwlwrf lwdn - TBOT tbot WIND wind @@ -1911,8 +1793,6 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN 1 @@ -1963,8 +1843,6 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START 1 @@ -2036,8 +1914,6 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END 1 @@ -2112,16 +1988,6 @@ 900 0 0 - -3600 - -3600 - -60 - -60 - -60 - -21600 - -21600 - -60 - -60 - -60 @@ -2188,8 +2054,6 @@ NULL CLMNCEP - CLMNCEP - CLMNCEP CORE2_NYF CORE2_IAF CORE_IAF_JRA @@ -2229,9 +2093,7 @@ valid values: 'copy','spval','nn','nnoni','nnonj' - nn - copy - copy + nn @@ -2386,16 +2248,6 @@ nearest coszen nearest - coszen - coszen - upper - linear - linear - coszen - coszen - upper - linear - linear coszen nearest nearest @@ -2488,25 +2340,6 @@ 3.0 3.0 3.0 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - From be16cabcf5e42a0bcd6c3f270b502674ad0fb868 Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 07:11:11 -0800 Subject: [PATCH 141/388] added ERA5 hourly & 6 hourly datm options --- .../datm/cime_config/config_component.xml | 10 +- .../cime_config/namelist_definition_datm.xml | 169 +++++++++++++++++- 2 files changed, 175 insertions(+), 4 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 94b0eab610d..73146daba5a 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -10,12 +10,14 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set GSWP3v1 data set + Fifth generation ECMWF reanalysis + Fifth generation ECMWF reanalysis,6 hourly data MOSART test data set using older NLDAS data NLDAS2 regional 0.125 degree data set over the U.S. (25-53N, 235-293E). WARNING: Garbage data will be produced for runs extending beyond this regional domain. Coupler hist data set (in this mode, it is strongly recommended that the model domain and the coupler history forcing are on the same domain) @@ -43,13 +45,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -68,6 +70,8 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEP CLMCRUNCEPv7 CLMGSWP3v1 + ERA5 + ERA5_6HR CLMMOSARTTEST CLMNLDAS2 CLM1PT diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 10d7111d433..a7b52113247 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -36,6 +36,8 @@ CLMCRUNCEP = Run with the CLM CRU NCEP V4 ( default ) forcing valid from 1900 to 2010 (force CLM) CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) + ERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -103,6 +105,26 @@ CLMGSWP3v1.Solar CLMGSWP3v1.Precip CLMGSWP3v1.TPQW + + ERA5.msdrswrf # mean surface direct shortwave radiation flux + ERA5.msdfswrf # mean surface diffuse shortwave radiation flux + ERA5.mcpr # mean convective precipitation rate + ERA5.mlspr # mean large-scale precipitation rate + ERA5.t2m # temperature at 2 m + ERA5.sp # surface pressure + ERA5.d2m # dew point temperature at 2 m + ERA5.w10 # wind speed at 10 m + ERA5.msdwlwrf # mean surface downward longwave radiation flux + + ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux + ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux + ERA5_6HR.mcpr # mean convective precipitation rate + ERA5_6HR.mlspr # mean large-scale precipitation rate + ERA5_6HR.t2m # temperature at 2 m + ERA5_6HR.sp # surface pressure + ERA5_6HR.d2m # dew point temperature at 2 m + ERA5_6HR.w10 # wind speed at 10 m + ERA5_6HR.msdwlwrf # mean surface downward longwave radiation flux CLMMOSARTTEST @@ -202,6 +224,8 @@ CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW + ERA5.msdrswrf,ERA5.msdfswrf,ERA5.mcpr,ERA5.mlspr, ERA5.t2m,ERA5.sp,ERA5.d2m,ERA5.w10,ERA5.msdwlwrf + ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW CORE2_NYF.GISS,CORE2_NYF.GXGXS,CORE2_NYF.NCEP @@ -234,6 +258,8 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 @@ -302,6 +328,8 @@ domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc nyf.giss.T62.051007.nc @@ -478,6 +506,24 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL3Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT/atm/datm7/NLDAS $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Solar $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Precip @@ -553,6 +599,24 @@ clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc clmforc.nldas.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Solr.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Prec.%ym.nc @@ -1523,6 +1587,60 @@ PSRF pbot FLDS lwdn + + msdrswrf swdndr + + + msdfswrf swdndf + + + mcpr precc + + + mlspr precl + + + t2m tbot + + + sp pbot + + + d2m tdew + + + w10 wind + + + msdwlwrf lwdn + + + msdrswrf swdndr + + + msdfswrf swdndf + + + mcpr precc + + + mlspr precl + + + t2m tbot + + + sp pbot + + + d2m tdew + + + w10 wind + + + msdwlwrf lwdn + TBOT tbot WIND wind @@ -1793,6 +1911,8 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN 1 @@ -1843,6 +1963,8 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START 1 @@ -1914,6 +2036,8 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END 1 @@ -1988,6 +2112,16 @@ 900 0 0 + -3600 + -3600 + -60 + -60 + -60 + -21600 + -21600 + -60 + -60 + -60 @@ -2054,6 +2188,8 @@ NULL CLMNCEP + CLMNCEP + CLMNCEP CORE2_NYF CORE2_IAF CORE_IAF_JRA @@ -2093,7 +2229,9 @@ valid values: 'copy','spval','nn','nnoni','nnonj' - nn + nn + copy + copy @@ -2248,6 +2386,16 @@ nearest coszen nearest + coszen + coszen + upper + linear + linear + coszen + coszen + upper + upper + upper coszen nearest nearest @@ -2340,6 +2488,25 @@ 3.0 3.0 3.0 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + From c69c16b95dccb833be1bc6f7edf8ef01a15cc241 Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 12:24:20 -0800 Subject: [PATCH 142/388] added ERA5 datm, not functional due to land ice error --- .../datm/cime_config/config_component.xml | 6 +- .../cime_config/namelist_definition_datm.xml | 130 +++++++++--------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 73146daba5a..6d10109075b 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -45,13 +45,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ELMERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -70,7 +70,7 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEP CLMCRUNCEPv7 CLMGSWP3v1 - ERA5 + ELMERA5 ERA5_6HR CLMMOSARTTEST CLMNLDAS2 diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index a7b52113247..2696126a8a5 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -36,8 +36,8 @@ CLMCRUNCEP = Run with the CLM CRU NCEP V4 ( default ) forcing valid from 1900 to 2010 (force CLM) CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) - ERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present - ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ELMERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -106,15 +106,15 @@ CLMGSWP3v1.Precip CLMGSWP3v1.TPQW - ERA5.msdrswrf # mean surface direct shortwave radiation flux - ERA5.msdfswrf # mean surface diffuse shortwave radiation flux - ERA5.mcpr # mean convective precipitation rate - ERA5.mlspr # mean large-scale precipitation rate - ERA5.t2m # temperature at 2 m - ERA5.sp # surface pressure - ERA5.d2m # dew point temperature at 2 m - ERA5.w10 # wind speed at 10 m - ERA5.msdwlwrf # mean surface downward longwave radiation flux + ELMERA5.msdrswrf # mean surface direct shortwave radiation flux + ELMERA5.msdfswrf # mean surface diffuse shortwave radiation flux + ELMERA5.mcpr # mean convective precipitation rate + ELMERA5.mlspr # mean large-scale precipitation rate + ELMERA5.t2m # temperature at 2 m + ELMERA5.sp # surface pressure + ELMERA5.d2m # dew point temperature at 2 m + ELMERA5.w10 # wind speed at 10 m + ELMERA5.msdwlwrf # mean surface downward longwave radiation flux ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux @@ -224,7 +224,7 @@ CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW - ERA5.msdrswrf,ERA5.msdfswrf,ERA5.mcpr,ERA5.mlspr, ERA5.t2m,ERA5.sp,ERA5.d2m,ERA5.w10,ERA5.msdwlwrf + ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW @@ -258,7 +258,7 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 @@ -328,7 +328,7 @@ domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc - domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc @@ -506,15 +506,15 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip3Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL3Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec @@ -599,15 +599,15 @@ clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc - elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc - elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc - elmforc.ERA5.c2018.0.25d.t2m.%ym.nc - elmforc.ERA5.c2018.0.25d.sp.%ym.nc - elmforc.ERA5.c2018.0.25d.d2m.%ym.nc - elmforc.ERA5.c2018.0.25d.w10.%ym.nc - elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc @@ -1587,31 +1587,31 @@ PSRF pbot FLDS lwdn - + msdrswrf swdndr - + msdfswrf swdndf - + mcpr precc - + mlspr precl - + t2m tbot - + sp pbot - + d2m tdew - + w10 wind - + msdwlwrf lwdn @@ -1911,7 +1911,7 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN @@ -1963,7 +1963,7 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START @@ -2036,7 +2036,7 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END @@ -2112,11 +2112,11 @@ 900 0 0 - -3600 - -3600 - -60 - -60 - -60 + -3600 + -3600 + -60 + -60 + -60 -21600 -21600 -60 @@ -2188,7 +2188,7 @@ NULL CLMNCEP - CLMNCEP + CLMNCEP CLMNCEP CORE2_NYF CORE2_IAF @@ -2230,7 +2230,7 @@ nn - copy + copy copy @@ -2386,11 +2386,11 @@ nearest coszen nearest - coszen - coszen - upper - linear - linear + coszen + coszen + upper + linear + linear coszen coszen upper @@ -2488,15 +2488,15 @@ 3.0 3.0 3.0 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 2.5 2.5 2.5 From 59b83c55809b2376c1dc02de65ab5d358945a637 Mon Sep 17 00:00:00 2001 From: Chloe Date: Wed, 7 Feb 2024 17:39:51 -0800 Subject: [PATCH 143/388] ERA% datm debugging --- .../datm/cime_config/config_component.xml | 2 ++ .../cime_config/namelist_definition_datm.xml | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 6d10109075b..b8fbcc930c5 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -15,6 +15,7 @@ QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set + CRUJRA data set GSWP3v1 data set Fifth generation ECMWF reanalysis Fifth generation ECMWF reanalysis,6 hourly data @@ -65,6 +66,7 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CORE_RYF8485_JRA CORE_RYF9091_JRA CORE_RYF0304_JRA + CRUJRA CLM_QIAN CLM_QIAN_WISO CLMCRUNCEP diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 2696126a8a5..8deec7e1946 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -223,6 +223,7 @@ CLM1PT.$ATM_GRID CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW + CRUJRA.Solar,CRUJRA.Precip,CRUJRA.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf @@ -256,6 +257,7 @@ null $DIN_LOC_ROOT/atm/datm7 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 @@ -325,6 +327,7 @@ domain.T62.050609.nc domain.T62.050609.nc domain.lnd.360x720_cruncep.130305.nc + domain.crujra.0.5x0.5.c200728.nc domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc @@ -497,6 +500,9 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Solar6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Precip6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/TPHWL6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Solar6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Precip6Hrly + $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/TPHWL6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL @@ -596,6 +602,9 @@ clmforc.cruncep.V7.c2016.0.5d.Solr.%ym.nc clmforc.cruncep.V7.c2016.0.5d.Prec.%ym.nc clmforc.cruncep.V7.c2016.0.5d.TPQWL.%ym.nc + clmforc.CRUJRA.0.5d.Solr.%ym.nc + clmforc.CRUJRA.0.5d.Prec.%ym.nc + clmforc.CRUJRA.0.5d.TPQWL.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc @@ -1574,6 +1583,18 @@ QBOT shum PSRF pbot + + FSDS swdn + + + PRECTmms precn + + + TBOT tbot + WIND wind + QBOT shum + PSRF pbot + FSDS swdn @@ -1915,6 +1936,7 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN 1 1 1 @@ -1967,6 +1989,7 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START 1 2010 2010 @@ -2040,6 +2063,7 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END 1 2011 2011 @@ -2137,7 +2161,7 @@ char streams shr_strdata_nml - CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,NULL + CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,CRUJRA,NULL general method that operates on the data. this is generally implemented in the data models but is set in the strdata method for @@ -2198,6 +2222,7 @@ COPYALL COPYALL COPYALL + CRUJRA @@ -2384,6 +2409,8 @@ nearest coszen nearest + coszen + nearest coszen nearest coszen From 653c3debe07b6d34e36d462bf9df38ad965dcf5f Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 8 Feb 2024 11:19:58 -0800 Subject: [PATCH 144/388] small datm & mcmodel changes ; ERA5 still too slow --- cime_config/machines/cmake_macros/intel_pm-cpu.cmake | 2 +- .../data_comps/datm/cime_config/namelist_definition_datm.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake index 0eab406627a..8eae9542d63 100644 --- a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake +++ b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake @@ -21,7 +21,7 @@ if (compile_threaded) endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS " -fp-model=precise") # and manually add precise +string(APPEND CMAKE_CXX_FLAGS "-mcmodel=medium -dynamic -fp-model=precise") # and manually add precise #message(STATUS "ndk CXXFLAGS=${CXXFLAGS}") string(APPEND CMAKE_Fortran_FLAGS " -fp-model=consistent -fimf-use-svml") diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 8deec7e1946..8d774503033 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -2421,8 +2421,8 @@ coszen coszen upper - upper - upper + linear + linear coszen nearest nearest From dcc49b2220b4d4c489893de6bba4e2e993f10cad Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 8 Feb 2024 17:29:07 -0800 Subject: [PATCH 145/388] functional ERA5 datm --- .../machines/cmake_macros/intel_pm-cpu.cmake | 2 +- .../datm/cime_config/config_component.xml | 4 +-- .../cime_config/namelist_definition_datm.xml | 29 +------------------ 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake index 8eae9542d63..0eab406627a 100644 --- a/cime_config/machines/cmake_macros/intel_pm-cpu.cmake +++ b/cime_config/machines/cmake_macros/intel_pm-cpu.cmake @@ -21,7 +21,7 @@ if (compile_threaded) endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS "-mcmodel=medium -dynamic -fp-model=precise") # and manually add precise +string(APPEND CMAKE_CXX_FLAGS " -fp-model=precise") # and manually add precise #message(STATUS "ndk CXXFLAGS=${CXXFLAGS}") string(APPEND CMAKE_Fortran_FLAGS " -fp-model=consistent -fimf-use-svml") diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index b8fbcc930c5..5a2fa9c927e 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -15,7 +15,6 @@ QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set - CRUJRA data set GSWP3v1 data set Fifth generation ECMWF reanalysis Fifth generation ECMWF reanalysis,6 hourly data @@ -46,7 +45,7 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml @@ -66,7 +65,6 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CORE_RYF8485_JRA CORE_RYF9091_JRA CORE_RYF0304_JRA - CRUJRA CLM_QIAN CLM_QIAN_WISO CLMCRUNCEP diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 8d774503033..0f7684f0072 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -223,7 +223,6 @@ CLM1PT.$ATM_GRID CLMCRUNCEP.Solar,CLMCRUNCEP.Precip,CLMCRUNCEP.TPQW CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW - CRUJRA.Solar,CRUJRA.Precip,CRUJRA.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf @@ -257,7 +256,6 @@ null $DIN_LOC_ROOT/atm/datm7 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 @@ -327,7 +325,6 @@ domain.T62.050609.nc domain.T62.050609.nc domain.lnd.360x720_cruncep.130305.nc - domain.crujra.0.5x0.5.c200728.nc domain.lnd.360x720.130305.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc @@ -500,9 +497,6 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Solar6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Precip6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/TPHWL6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Solar6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/Precip6Hrly - $DIN_LOC_ROOT_CLMFORC/atm_forcing.CRUJRA/TPHWL6Hrly $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL @@ -602,9 +596,6 @@ clmforc.cruncep.V7.c2016.0.5d.Solr.%ym.nc clmforc.cruncep.V7.c2016.0.5d.Prec.%ym.nc clmforc.cruncep.V7.c2016.0.5d.TPQWL.%ym.nc - clmforc.CRUJRA.0.5d.Solr.%ym.nc - clmforc.CRUJRA.0.5d.Prec.%ym.nc - clmforc.CRUJRA.0.5d.TPQWL.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc @@ -1583,18 +1574,6 @@ QBOT shum PSRF pbot - - FSDS swdn - - - PRECTmms precn - - - TBOT tbot - WIND wind - QBOT shum - PSRF pbot - FSDS swdn @@ -1936,7 +1915,6 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN 1 1 1 @@ -1989,7 +1967,6 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START 1 2010 2010 @@ -2063,7 +2040,6 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END 1 2011 2011 @@ -2161,7 +2137,7 @@ char streams shr_strdata_nml - CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,CRUJRA,NULL + CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,IAF_JRA_1p5,CORE_RYF_JRA,NULL general method that operates on the data. this is generally implemented in the data models but is set in the strdata method for @@ -2222,7 +2198,6 @@ COPYALL COPYALL COPYALL - CRUJRA @@ -2409,8 +2384,6 @@ nearest coszen nearest - coszen - nearest coszen nearest coszen From 03cc80f657b80ec3fcf230e065e232afc523119d Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 25 Mar 2024 09:58:07 -0700 Subject: [PATCH 146/388] Renames ERA5_6HR to ERA56HR --- .../datm/cime_config/config_component.xml | 16 ++- .../cime_config/namelist_definition_datm.xml | 128 +++++++++--------- 2 files changed, 75 insertions(+), 69 deletions(-) diff --git a/components/data_comps/datm/cime_config/config_component.xml b/components/data_comps/datm/cime_config/config_component.xml index 5a2fa9c927e..cb982f52fcf 100644 --- a/components/data_comps/datm/cime_config/config_component.xml +++ b/components/data_comps/datm/cime_config/config_component.xml @@ -10,14 +10,14 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set CLM CRU NCEP v7 data set GSWP3v1 data set Fifth generation ECMWF reanalysis - Fifth generation ECMWF reanalysis,6 hourly data + Fifth generation ECMWF reanalysis,6 hourly data MOSART test data set using older NLDAS data NLDAS2 regional 0.125 degree data set over the U.S. (25-53N, 235-293E). WARNING: Garbage data will be produced for runs extending beyond this regional domain. Coupler hist data set (in this mode, it is strongly recommended that the model domain and the coupler history forcing are on the same domain) @@ -45,13 +45,13 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ERA5_6HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,ELMERA5,ERA56HR,CLMMOSARTTEST,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,IAF_JRA_1p5,CORE_IAF_JRA_1p4_2018,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,CFSv2,CFSR CORE2_NYF run_component_datm env_run.xml Mode for data atmosphere component. CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. - CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ELMERA5,ERA5_6HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. + CLM_QIAN, CLMCRUNCEP, CLMCRUNCEPv7, CLMGSWP3v1, ELMERA5,ERA56HR, CLMMOSARTTEST, CLMNLDAS2 and CLM1PT are modes using observational data for forcing prognostic land components. WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. WARNING for CLMGSWP3v1: Humidity is identically zero for last time step in Dec/2013 and all of 2014 so you should NOT use 2014 data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). @@ -71,7 +71,7 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). CLMCRUNCEPv7 CLMGSWP3v1 ELMERA5 - ERA5_6HR + ERA56HR CLMMOSARTTEST CLMNLDAS2 CLM1PT @@ -249,6 +249,8 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START run_component_datm env_run.xml @@ -292,6 +294,8 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). 2005 2002 1958 + 1979 + 1979 run_component_datm env_run.xml @@ -336,6 +340,8 @@ data (see cime issue #3653 -- https://github.com/ESMCI/cime/issues/3653). 2003 2016 2020 + 1979 + 1979 run_component_datm env_run.xml diff --git a/components/data_comps/datm/cime_config/namelist_definition_datm.xml b/components/data_comps/datm/cime_config/namelist_definition_datm.xml index 0f7684f0072..529e79a03f6 100644 --- a/components/data_comps/datm/cime_config/namelist_definition_datm.xml +++ b/components/data_comps/datm/cime_config/namelist_definition_datm.xml @@ -37,7 +37,7 @@ CLMCRUNCEPv7 = Run with the CLM CRU NCEP V7 forcing valid from 1900 to 2010 (force CLM) CLMGSWP3v1 = Run with the CLM GSWP3 V1 forcing (force CLM) ELMERA5 = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present - ERA5_6HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present + ERA56HR = Run with the ELM fifth generation ECMWF reanalysis from 1979 to present CLMMOSARTTEST = Run with the CLM NLDAS data (force CLM) for testing MOSART CLMNLDAS2 = Run with the CLM NLDAS2 regional forcing valid from 1980 to 2018 (force CLM) CLM1PT = Run with supplied single point data (force CLM) @@ -116,15 +116,15 @@ ELMERA5.w10 # wind speed at 10 m ELMERA5.msdwlwrf # mean surface downward longwave radiation flux - ERA5_6HR.msdrswrf # mean surface direct shortwave radiation flux - ERA5_6HR.msdfswrf # mean surface diffuse shortwave radiation flux - ERA5_6HR.mcpr # mean convective precipitation rate - ERA5_6HR.mlspr # mean large-scale precipitation rate - ERA5_6HR.t2m # temperature at 2 m - ERA5_6HR.sp # surface pressure - ERA5_6HR.d2m # dew point temperature at 2 m - ERA5_6HR.w10 # wind speed at 10 m - ERA5_6HR.msdwlwrf # mean surface downward longwave radiation flux + ERA56HR.msdrswrf # mean surface direct shortwave radiation flux + ERA56HR.msdfswrf # mean surface diffuse shortwave radiation flux + ERA56HR.mcpr # mean convective precipitation rate + ERA56HR.mlspr # mean large-scale precipitation rate + ERA56HR.t2m # temperature at 2 m + ERA56HR.sp # surface pressure + ERA56HR.d2m # dew point temperature at 2 m + ERA56HR.w10 # wind speed at 10 m + ERA56HR.msdwlwrf # mean surface downward longwave radiation flux CLMMOSARTTEST @@ -225,7 +225,7 @@ CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW ELMERA5.msdrswrf,ELMERA5.msdfswrf,ELMERA5.mcpr,ELMERA5.mlspr,ELMERA5.t2m,ELMERA5.sp,ELMERA5.d2m,ELMERA5.w10,ELMERA5.msdwlwrf - ERA5_6HR.msdrswrf,ERA5_6HR.msdfswrf,ERA5_6HR.mcpr,ERA5_6HR.mlspr,ERA5_6HR.t2m,ERA5_6HR.sp,ERA5_6HR.d2m,ERA5_6HR.w10,ERA5_6HR.msdwlwrf + ERA56HR.msdrswrf,ERA56HR.msdfswrf,ERA56HR.mcpr,ERA56HR.mlspr,ERA56HR.t2m,ERA56HR.sp,ERA56HR.d2m,ERA56HR.w10,ERA56HR.msdwlwrf CLMMOSARTTEST CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW CORE2_NYF.GISS,CORE2_NYF.GXGXS,CORE2_NYF.NCEP @@ -259,7 +259,7 @@ $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614 - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 $DIN_LOC_ROOT/share/domains/domain.clm $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.V5.c140715 $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516 @@ -329,7 +329,7 @@ domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.360x720_gswp3.0v1.c170606.nc domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc - domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc domain.lnd.nldas2_0224x0464_c110415.nc domain.lnd.0.125nldas2_0.125nldas2.190410.nc nyf.giss.T62.051007.nc @@ -515,15 +515,15 @@ $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind - $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn $DIN_LOC_ROOT/atm/datm7/NLDAS $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Solar $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Precip @@ -608,15 +608,15 @@ elmforc.ERA5.c2018.0.25d.d2m.%ym.nc elmforc.ERA5.c2018.0.25d.w10.%ym.nc elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc - elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc - elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc - elmforc.ERA5.c2018.0.25d.t2m.%ym.nc - elmforc.ERA5.c2018.0.25d.sp.%ym.nc - elmforc.ERA5.c2018.0.25d.d2m.%ym.nc - elmforc.ERA5.c2018.0.25d.w10.%ym.nc - elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdrswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.msdfswrf.%ym.nc + elmforc.ERA5.c2018.0.25d.mcpr.%ym.nc + elmforc.ERA5.c2018.0.25d.mlspr.%ym.nc + elmforc.ERA5.c2018.0.25d.t2m.%ym.nc + elmforc.ERA5.c2018.0.25d.sp.%ym.nc + elmforc.ERA5.c2018.0.25d.d2m.%ym.nc + elmforc.ERA5.c2018.0.25d.w10.%ym.nc + elmforc.ERA5.c2018.0.25d.msdwlwrf.%ym.nc clmforc.nldas.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Solr.%ym.nc ctsmforc.NLDAS2.0.125d.v1.Prec.%ym.nc @@ -1614,31 +1614,31 @@ msdwlwrf lwdn - + msdrswrf swdndr - + msdfswrf swdndf - + mcpr precc - + mlspr precl - + t2m tbot - + sp pbot - + d2m tdew - + w10 wind - + msdwlwrf lwdn @@ -1912,7 +1912,7 @@ $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN - $DATM_CLMNCEP_YR_ALIGN + $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN $DATM_CLMNCEP_YR_ALIGN 1 @@ -1964,7 +1964,7 @@ $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START - $DATM_CLMNCEP_YR_START + $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START $DATM_CLMNCEP_YR_START 1 @@ -2037,7 +2037,7 @@ $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END - $DATM_CLMNCEP_YR_END + $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END $DATM_CLMNCEP_YR_END 1 @@ -2117,11 +2117,11 @@ -60 -60 -60 - -21600 - -21600 - -60 - -60 - -60 + -21600 + -21600 + -60 + -60 + -60 @@ -2189,7 +2189,7 @@ NULL CLMNCEP CLMNCEP - CLMNCEP + CLMNCEP CORE2_NYF CORE2_IAF CORE_IAF_JRA @@ -2231,7 +2231,7 @@ nn copy - copy + copy @@ -2391,11 +2391,11 @@ upper linear linear - coszen - coszen - upper - linear - linear + coszen + coszen + upper + linear + linear coszen nearest nearest @@ -2497,15 +2497,15 @@ 2.5 2.5 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 - 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 + 2.5 From 24b7f10b23ce576bd0341b946438ee6e833ca05c Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 25 Mar 2024 10:03:23 -0700 Subject: [PATCH 147/388] Adds compsets for ERA5 and ERA5 6Hourly DATM --- components/elm/cime_config/config_compsets.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/elm/cime_config/config_compsets.xml b/components/elm/cime_config/config_compsets.xml index e5173644075..0192e4189b7 100644 --- a/components/elm/cime_config/config_compsets.xml +++ b/components/elm/cime_config/config_compsets.xml @@ -24,6 +24,16 @@ 1850_DATM%QIA_ELM%SPBC_SICE_SOCN_MOSART_SGLC_SWAV + + IERA5ELM + 2000_DATM%ERA5_ELM%SP_SICE_SOCN_MOSART_SGLC_SWAV + + + + IERA56HRELM + 2000_DATM%ERA56HR_ELM%SP_SICE_SOCN_MOSART_SGLC_SWAV + + IELM 2000_DATM%QIA_ELM%SP_SICE_SOCN_MOSART_SGLC_SWAV From dd908211ff1fe8a73a125a2fd6d106ee398fa578 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 25 Mar 2024 11:44:50 -0700 Subject: [PATCH 148/388] Adds two tests --- cime_config/tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cime_config/tests.py b/cime_config/tests.py index 7c3e914cb0c..b29abd4b457 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -48,6 +48,8 @@ "ERS.f19_g16.I1850GSWCNPECACNTBC.elm-eca_f19_g16_I1850GSWCNPECACNTBC", "ERS.f19_g16.I20TRGSWCNPECACNTBC.elm-eca_f19_g16_I20TRGSWCNPECACNTBC", "ERS.f19_g16.I20TRGSWCNPRDCTCBC.elm-ctc_f19_g16_I20TRGSWCNPRDCTCBC", + "ERS.f19_g16.IERA5ELM", + "ERS.f19_g16.IERA56HRELM", ) }, From 0e14c5bf6d76fabe073c68bba1d82759b1394054 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 13 Apr 2024 15:12:59 -0500 Subject: [PATCH 149/388] Updates the tests to only use 1-month of DATM data --- cime_config/tests.py | 4 +-- .../testmods_dirs/elm/era5/shell_commands | 3 ++ .../era5/user_datm.streams.txt.ELMERA5.d2m | 35 +++++++++++++++++++ .../era5/user_datm.streams.txt.ELMERA5.mcpr | 35 +++++++++++++++++++ .../era5/user_datm.streams.txt.ELMERA5.mlspr | 35 +++++++++++++++++++ .../user_datm.streams.txt.ELMERA5.msdfswrf | 35 +++++++++++++++++++ .../user_datm.streams.txt.ELMERA5.msdrswrf | 35 +++++++++++++++++++ .../user_datm.streams.txt.ELMERA5.msdwlwrf | 35 +++++++++++++++++++ .../elm/era5/user_datm.streams.txt.ELMERA5.sp | 35 +++++++++++++++++++ .../era5/user_datm.streams.txt.ELMERA5.t2m | 35 +++++++++++++++++++ .../era5/user_datm.streams.txt.ELMERA5.w10 | 35 +++++++++++++++++++ .../testmods_dirs/elm/era56hr/shell_commands | 4 +++ .../era56hr/user_datm.streams.txt.ERA56HR.d2m | 35 +++++++++++++++++++ .../user_datm.streams.txt.ERA56HR.mcpr | 35 +++++++++++++++++++ .../user_datm.streams.txt.ERA56HR.mlspr | 35 +++++++++++++++++++ .../user_datm.streams.txt.ERA56HR.msdfswrf | 35 +++++++++++++++++++ .../user_datm.streams.txt.ERA56HR.msdrswrf | 35 +++++++++++++++++++ .../user_datm.streams.txt.ERA56HR.msdwlwrf | 35 +++++++++++++++++++ .../era56hr/user_datm.streams.txt.ERA56HR.sp | 35 +++++++++++++++++++ .../era56hr/user_datm.streams.txt.ERA56HR.t2m | 35 +++++++++++++++++++ .../era56hr/user_datm.streams.txt.ERA56HR.w10 | 35 +++++++++++++++++++ 21 files changed, 639 insertions(+), 2 deletions(-) create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/shell_commands create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.d2m create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mcpr create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mlspr create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdfswrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdrswrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdwlwrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.sp create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.t2m create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.w10 create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/shell_commands create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.d2m create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mcpr create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mlspr create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdfswrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdrswrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdwlwrf create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.sp create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.t2m create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.w10 diff --git a/cime_config/tests.py b/cime_config/tests.py index b29abd4b457..135dc0607b5 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -48,8 +48,8 @@ "ERS.f19_g16.I1850GSWCNPECACNTBC.elm-eca_f19_g16_I1850GSWCNPECACNTBC", "ERS.f19_g16.I20TRGSWCNPECACNTBC.elm-eca_f19_g16_I20TRGSWCNPECACNTBC", "ERS.f19_g16.I20TRGSWCNPRDCTCBC.elm-ctc_f19_g16_I20TRGSWCNPRDCTCBC", - "ERS.f19_g16.IERA5ELM", - "ERS.f19_g16.IERA56HRELM", + "ERS.f19_g16.IERA5ELM.elm-era5", + "ERS.f19_g16.IERA56HRELM.elm-er56hr", ) }, diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/shell_commands new file mode 100644 index 00000000000..b69b9cd6ee9 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/shell_commands @@ -0,0 +1,3 @@ +CASEDIR=`./xmlquery CASEROOT --value` +SRCROOT=`./xmlquery SRCROOT --value` +cp $SRCROOT/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.* $CASEDIR diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.d2m b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.d2m new file mode 100644 index 00000000000..bae3cf6a147 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.d2m @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + d2m tdew + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/tdew + + + elmforc.ERA5.c2018.0.25d.d2m.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mcpr b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mcpr new file mode 100644 index 00000000000..5413ff5ccbd --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mcpr @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + mcpr precc + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + + + elmforc.ERA5.c2018.0.25d.mcpr.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mlspr b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mlspr new file mode 100644 index 00000000000..9696d75511e --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.mlspr @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + mlspr precl + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/prec + + + elmforc.ERA5.c2018.0.25d.mlspr.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdfswrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdfswrf new file mode 100644 index 00000000000..8229e921e0c --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdfswrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdfswrf swdndf + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + + + elmforc.ERA5.c2018.0.25d.msdfswrf.1979-01.nc + + + -3600 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdrswrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdrswrf new file mode 100644 index 00000000000..42ec79040ca --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdrswrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdrswrf swdndr + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/swdn + + + elmforc.ERA5.c2018.0.25d.msdrswrf.1979-01.nc + + + -3600 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdwlwrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdwlwrf new file mode 100644 index 00000000000..e4aa32907a0 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.msdwlwrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdwlwrf lwdn + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/lwdn + + + elmforc.ERA5.c2018.0.25d.msdwlwrf.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.sp b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.sp new file mode 100644 index 00000000000..dec0ed40e09 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.sp @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + sp pbot + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/pbot + + + elmforc.ERA5.c2018.0.25d.sp.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.t2m b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.t2m new file mode 100644 index 00000000000..c65b62c9399 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.t2m @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + t2m tbot + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/tbot + + + elmforc.ERA5.c2018.0.25d.t2m.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.w10 b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.w10 new file mode 100644 index 00000000000..e66da30e438 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era5/user_datm.streams.txt.ELMERA5.w10 @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + w10 wind + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.0.25d.v5.c180614/wind + + + elmforc.ERA5.c2018.0.25d.w10.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/shell_commands new file mode 100644 index 00000000000..13c1a77803f --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/shell_commands @@ -0,0 +1,4 @@ +CASEDIR=`./xmlquery CASEROOT --value` +SRCROOT=`./xmlquery SRCROOT --value` +cp $SRCROOT/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.* $CASEDIR + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.d2m b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.d2m new file mode 100644 index 00000000000..b40af4edcd5 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.d2m @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + d2m tdew + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tdew + + + elmforc.ERA5.c2018.0.25d.d2m.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mcpr b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mcpr new file mode 100644 index 00000000000..697ac03f515 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mcpr @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + mcpr precc + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + + + elmforc.ERA5.c2018.0.25d.mcpr.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mlspr b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mlspr new file mode 100644 index 00000000000..f0f622cb54b --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.mlspr @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + mlspr precl + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/prec + + + elmforc.ERA5.c2018.0.25d.mlspr.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdfswrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdfswrf new file mode 100644 index 00000000000..78391fe9729 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdfswrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdfswrf swdndf + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + + + elmforc.ERA5.c2018.0.25d.msdfswrf.1979-01.nc + + + -21600 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdrswrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdrswrf new file mode 100644 index 00000000000..e49c036d486 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdrswrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdrswrf swdndr + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/swdn + + + elmforc.ERA5.c2018.0.25d.msdrswrf.1979-01.nc + + + -21600 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdwlwrf b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdwlwrf new file mode 100644 index 00000000000..cfff16d580d --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.msdwlwrf @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + msdwlwrf lwdn + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/lwdn + + + elmforc.ERA5.c2018.0.25d.msdwlwrf.1979-01.nc + + + -60 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.sp b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.sp new file mode 100644 index 00000000000..692b57e1b02 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.sp @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + sp pbot + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/pbot + + + elmforc.ERA5.c2018.0.25d.sp.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.t2m b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.t2m new file mode 100644 index 00000000000..f214f84e2a5 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.t2m @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + t2m tbot + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/tbot + + + elmforc.ERA5.c2018.0.25d.t2m.1979-01.nc + + + 0 + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.w10 b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.w10 new file mode 100644 index 00000000000..42cbd413863 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/era56hr/user_datm.streams.txt.ERA56HR.w10 @@ -0,0 +1,35 @@ + + + + GENERIC + + + + time time + xc lon + yc lat + area area + mask mask + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614 + + + domain.lnd.era5_721x1440_rdrlat_EC30to60E2r2.221115.nc + + + + + w10 wind + + + /lcrc/group/e3sm/data/inputdata/atm/datm7/atm_forcing.datm7.ERA.6HRLY.0.25d.v5.c180614/wind + + + elmforc.ERA5.c2018.0.25d.w10.1979-01.nc + + + 0 + + + From b41bc937f6d48b72c89e5b2c19a28553aad1fca0 Mon Sep 17 00:00:00 2001 From: Chloe Date: Mon, 29 Apr 2024 13:36:50 -0700 Subject: [PATCH 150/388] add test for use_firn_percolation_and_compaction --- .../testmods_dirs/elm/firn_percolation_compaction/user_nl_elm | 1 + 1 file changed, 1 insertion(+) create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/firn_percolation_compaction/user_nl_elm diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/firn_percolation_compaction/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/firn_percolation_compaction/user_nl_elm new file mode 100644 index 00000000000..36b30a3621d --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/firn_percolation_compaction/user_nl_elm @@ -0,0 +1 @@ +use_firn_percolation_and_compaction = .true. From cb43f07642f97625c9c3a66afda40b0322449326 Mon Sep 17 00:00:00 2001 From: daleihao Date: Thu, 2 May 2024 06:21:00 -0700 Subject: [PATCH 151/388] update mapping files --- components/elm/bld/namelist_files/namelist_defaults.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 0132320a215..9a529405564 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -1660,7 +1660,7 @@ this mask will have smb calculated over the entire global land surface lnd/clm2/mappingdata/maps/0.25x0.25/map_0.01x0.01_nomask_to_0.25x0.25_nomask_aave_da_c240424.nc +>lnd/clm2/mappingdata/maps/0.25x0.25/map_0.01x0.01_nomask_to_0.25x0.25_nomask_aave_da_c240501.nc @@ -1712,7 +1712,7 @@ this mask will have smb calculated over the entire global land surface lnd/clm2/mappingdata/maps/0.5x0.5/map_1km-merge-10min_HYDRO1K-merge-nomask_to_0.5x0.5_nomask_aave_da_c190417.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_0.01x0.01_nomask_to_0.5x0.5_nomask_aave_da_c240424.nc +>lnd/clm2/mappingdata/maps/0.5x0.5/map_0.01x0.01_nomask_to_0.5x0.5_nomask_aave_da_c240501.nc From d6411d8d61d5171f14b977e75f12fa0aae94a83c Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Sat, 4 May 2024 11:05:52 -0500 Subject: [PATCH 152/388] Adds ^xpmem and grid TL319_r05_IcoswISC30E3r5 bfb --- cime_config/config_grids.xml | 10 ++++++++++ cime_config/machines/config_machines.xml | 1 + 2 files changed, 11 insertions(+) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index b9ae00da019..56a18388676 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -599,6 +599,16 @@ IcoswISC30E3r5 + + TL319 + r05 + IcoswISC30E3r5 + r05 + null + null + IcoswISC30E3r5 + + TL319 TL319 diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 486948892aa..00087a00a7d 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -2622,6 +2622,7 @@ $SHELL{dirname $(dirname $(which nf-config))} $SHELL{dirname $(dirname $(which pnetcdf_version))} ^lockedfile,individual + ^xpmem 128M From cb21d80faed249c2a4ff96ce01c810c913f91458 Mon Sep 17 00:00:00 2001 From: dqwu Date: Fri, 3 May 2024 15:34:54 -0500 Subject: [PATCH 153/388] Adding optional argument to retrieve ncid from ncd_defvar_bygrid The subroutine ncd_defvar_bygrid internally uses a local varid to invoke ncd_defvar_bynf. Introduce a new argument to optionally return the varid to the caller. --- components/elm/src/main/ncdio_pio.F90.in | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/elm/src/main/ncdio_pio.F90.in b/components/elm/src/main/ncdio_pio.F90.in index 51160c3e8cc..6fbaba0b710 100644 --- a/components/elm/src/main/ncdio_pio.F90.in +++ b/components/elm/src/main/ncdio_pio.F90.in @@ -1070,7 +1070,7 @@ contains dim1name, dim2name, dim3name, dim4name, dim5name, & long_name, standard_name, units, cell_method, missing_value, fill_value, & imissing_value, ifill_value, switchdim, comment, & - flag_meanings, flag_values, nvalid_range ) + flag_meanings, flag_values, nvalid_range, varid ) ! ! !DESCRIPTION: ! Define a netcdf variable @@ -1097,12 +1097,13 @@ contains logical , intent(in), optional :: switchdim ! true=> permute dim1 and dim2 for output integer , intent(in), optional :: flag_values(:) ! attribute for int integer , intent(in), optional :: nvalid_range(2) ! attribute for int + integer , intent(out), optional :: varid ! returned var id ! ! !LOCAL VARIABLES: integer :: n ! indices integer :: ndims ! dimension counter integer :: dimid(5) ! dimension ids - integer :: varid ! variable id + integer :: varid_tmp ! variable id (temporary) integer :: itmp ! temporary character(len=256) :: str ! temporary character(len=*),parameter :: subname='ncd_defvar_bygrid' ! subroutine name @@ -1135,13 +1136,17 @@ contains end do end if - call ncd_defvar_bynf(ncid,varname,xtype,ndims,dimid,varid, & + call ncd_defvar_bynf(ncid,varname,xtype,ndims,dimid,varid_tmp, & long_name=long_name, standard_name=standard_name,units=units, cell_method=cell_method, & missing_value=missing_value, fill_value=fill_value, & imissing_value=imissing_value, ifill_value=ifill_value, & comment=comment, flag_meanings=flag_meanings, & flag_values=flag_values, nvalid_range=nvalid_range ) + if (present(varid)) then + varid = varid_tmp + end if + end subroutine ncd_defvar_bygrid !------------------------------------------------------------------------ From ef89e272e0f66d1a18463c215cafad4a009ec76a Mon Sep 17 00:00:00 2001 From: Jon Wolfe Date: Mon, 6 May 2024 12:55:30 -0500 Subject: [PATCH 154/388] Move extrasnowlayers test to e3sm_landice_developer suite --- cime_config/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/tests.py b/cime_config/tests.py index 0ead7c13bcb..2760215ba7d 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -124,6 +124,7 @@ "tests" : ( "SMS.ne30pg2_r05_EC30to60E2r2_gis20.IGELM_MLI.elm-gis20kmSMS", "ERS.ne30pg2_r05_EC30to60E2r2_gis20.IGELM_MLI.elm-gis20kmERS", + "SMS.ne30_oECv3_gis.IGELM_MLI.elm-extrasnowlayers", ) }, @@ -256,7 +257,6 @@ "tests" : ( "ERS_P480_Ld5.TL319_IcoswISC30E3r5.GMPAS-JRA1p5-DIB-PISMF.mpaso-jra_1958", "PEM_P480_Ld5.TL319_IcoswISC30E3r5.GMPAS-JRA1p5-DIB-PISMF.mpaso-jra_1958", - "SMS.ne30_oECv3_gis.IGELM_MLI.elm-extrasnowlayers", ) }, From 2272b67514332b2ec98f413c4d8614d766c66df2 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Mon, 6 May 2024 13:27:37 -0500 Subject: [PATCH 155/388] Split init_zbgc into three calls -First uses init_parameters to initialize bgc namelist parameters -Second (icepack_init_zbgc_tracer_indices) calls bgc indexing and array definitions. -Third defines parameter arrays for bgc (init_zbgc) bfb (round-off level in bgc) --- .../src/shared/mpas_seaice_icepack.F | 168 +++++++++--------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index b08ed7c863c..6c787048ad1 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -12908,6 +12908,8 @@ end subroutine seaice_column_reinitialize_oceanic_fluxes subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) use icepack_intfc, only: icepack_init_zbgc + use icepack_intfc, only: icepack_init_zbgc_tracer_indices + use icepack_intfc, only: icepack_init_parameters use icepack_intfc, only: icepack_query_parameters type(domain_type), intent(in) :: & @@ -13252,90 +13254,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) allocate(tracerObject % index_dissolvedIronConcLayer(maxIronType)) tracerObject % nDissolvedIronIndex = nDissolvedIron - call icepack_init_zbgc(& - nblyr=nBioLayers, & - nilyr=nIceLayers, & - nslyr=nSnowLayers, & - n_algae_in=nAlgae, & - n_zaero_in=nzAerosols, & - n_doc_in=nDOC, & - n_dic_in=nDIC, & - n_don_in=nDON, & - n_fed_in=nDissolvedIron, & - n_fep_in=nParticulateIron, & - trcr_base=tracerObject % firstAncestorMask, & - trcr_depend=tracerObject % parentIndex, & - n_trcr_strata=tracerObject % ancestorNumber, & - nt_strata=tracerObject % ancestorIndices, & - nbtrcr_sw_out=tracerObject % nBioTracersShortwave, & - tr_brine_in=config_use_brine, & - nt_fbri_out=tracerObject % index_brineFraction,& - ntrcr_out=tracerObject % nTracers, & - nbtrcr_out=tracerObject % nBioTracers, & - ntrcr_o_out=tracerObject % nTracersNotBio, & - nt_bgc_Nit_out=tracerObject % index_nitrateConc, & - nt_bgc_Am_out=tracerObject % index_ammoniumConc, & - nt_bgc_Sil_out=tracerObject % index_silicateConc, & - nt_bgc_DMS_out=tracerObject % index_DMSConc, & - nt_bgc_PON_out=tracerObject % index_nonreactiveConc, & - nt_bgc_N_out=tracerObject % index_algaeConc, & - nt_bgc_C_out=tracerObject % index_algalCarbon, & - nt_bgc_chl_out=tracerObject % index_algalChlorophyll, & - nt_bgc_DOC_out=tracerObject % index_DOCConc, & - nt_bgc_DON_out=tracerObject % index_DONConc, & - nt_bgc_DIC_out=tracerObject % index_DICConc, & - nt_zaero_out=tracerObject % index_verticalAerosolsConc, & - nt_bgc_DMSPp_out=tracerObject % index_DMSPpConc, & - nt_bgc_DMSPd_out=tracerObject % index_DMSPdConc, & - nt_bgc_Fed_out=tracerObject % index_dissolvedIronConc, & - nt_bgc_Fep_out=tracerObject % index_particulateIronConc, & - nt_zbgc_frac_out=tracerObject % index_mobileFraction, & - tr_bgc_Nit_in=config_use_nitrate, & - tr_bgc_Am_in=config_use_ammonium, & - tr_bgc_Sil_in=config_use_silicate, & - tr_bgc_DMS_in=config_use_DMS, & - tr_bgc_PON_in=config_use_nonreactive, & - tr_bgc_N_in=use_nitrogen, & - tr_bgc_C_in=config_use_carbon, & - tr_bgc_chl_in=config_use_chlorophyll, & - tr_bgc_DON_in=config_use_DON, & - tr_bgc_Fe_in=config_use_iron,& - tr_zaero_in=config_use_zaerosols, & - nlt_zaero_sw_out=tracerObject % index_verticalAerosolsConcShortwave, & - nlt_chl_sw_out=tracerObject % index_chlorophyllShortwave, & - nlt_bgc_N_out=tracerObject % index_algaeConcLayer, & - nlt_bgc_Nit_out=tracerObject % index_nitrateConcLayer, & - nlt_bgc_Am_out=tracerObject % index_ammoniumConcLayer, & - nlt_bgc_Sil_out=tracerObject % index_silicateConcLayer, & - nlt_bgc_DMS_out=tracerObject % index_DMSConcLayer, & - nlt_bgc_DMSPp_out=tracerObject % index_DMSPpConcLayer, & - nlt_bgc_DMSPd_out=tracerObject % index_DMSPdConcLayer, & - nlt_bgc_C_out=tracerObject % index_algalCarbonLayer, & - nlt_bgc_chl_out=tracerObject % index_algalChlorophyllLayer, & - nlt_bgc_DIC_out=tracerObject % index_DICConcLayer, & - nlt_bgc_DOC_out=tracerObject % index_DOCConcLayer, & - nlt_bgc_PON_out=tracerObject % index_nonreactiveConcLayer, & - nlt_bgc_DON_out=tracerObject % index_DONConcLayer, & - nlt_bgc_Fed_out=tracerObject % index_dissolvedIronConcLayer, & - nlt_bgc_Fep_out=tracerObject % index_particulateIronConcLayer, & - nlt_zaero_out=tracerObject % index_verticalAerosolsConcLayer, & - nt_bgc_hum_out=tracerObject % index_humicsConc, & - nlt_bgc_hum_out=tracerObject % index_humicsConcLayer, & - tr_bgc_hum_in=config_use_humics, & - skl_bgc_in=config_use_skeletal_biochemistry, & - z_tracers_in=config_use_vertical_tracers, & - dEdd_algae_in=config_use_shortwave_bioabsorption, & - solve_zbgc_in=config_use_vertical_biochemistry, & - bio_index_o_out=tracerObject % index_LayerIndexToDataArray, & - bio_index_out=tracerObject % index_LayerIndexToBioIndex, & - frazil_scav_in=config_fraction_biotracer_in_frazil, & - initbio_frac_in=config_new_ice_fraction_biotracer, & - max_algae_in=maxAlgaeType, & - max_doc_in=maxDOCType, & - max_dic_in=maxDICType, & - max_don_in=maxDONType, & - max_fe_in=maxIronType, & - max_aero_in=maxAerosolType, & + call icepack_init_parameters(& ratio_Si2N_diatoms_in=config_ratio_Si_to_N_diatoms, & ratio_Si2N_sp_in=config_ratio_Si_to_N_small_plankton, & ratio_Si2N_phaeo_in=config_ratio_Si_to_N_phaeocystis, & @@ -13430,9 +13349,90 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) dmspdtype_in=config_mobility_type_DMSPd, & silicatetype_in=config_mobility_type_silicate, & humtype_in=config_mobility_type_humics, & + frazil_scav_in=config_fraction_biotracer_in_frazil, & + initbio_frac_in=config_new_ice_fraction_biotracer, & tau_min_in=config_rapid_mobile_to_stationary_time, & tau_max_in=config_long_mobile_to_stationary_time) + call icepack_init_zbgc_tracer_indices(& + nilyr_in=nIceLayers, & + nslyr_in=nSnowLayers, & + nblyr_in=nBioLayers, & + n_algae_in=nAlgae, & + n_zaero_in=nzAerosols, & + n_doc_in=nDOC, & + n_dic_in=nDIC, & + n_don_in=nDON, & + n_fed_in=nDissolvedIron, & + n_fep_in=nParticulateIron, & + trcr_base=tracerObject % firstAncestorMask, & + trcr_depend=tracerObject % parentIndex, & + n_trcr_strata=tracerObject % ancestorNumber, & + nt_strata=tracerObject % ancestorIndices, & + nbtrcr_sw_out=tracerObject % nBioTracersShortwave, & + tr_brine_in=config_use_brine, & + nt_fbri_out=tracerObject % index_brineFraction,& + ntrcr_out=tracerObject % nTracers, & + nbtrcr_out=tracerObject % nBioTracers, & + ntrcr_o_out=tracerObject % nTracersNotBio, & + nt_bgc_Nit_out=tracerObject % index_nitrateConc, & + nt_bgc_Am_out=tracerObject % index_ammoniumConc, & + nt_bgc_Sil_out=tracerObject % index_silicateConc, & + nt_bgc_DMS_out=tracerObject % index_DMSConc, & + nt_bgc_PON_out=tracerObject % index_nonreactiveConc, & + nt_bgc_N_out=tracerObject % index_algaeConc, & + nt_bgc_C_out=tracerObject % index_algalCarbon, & + nt_bgc_chl_out=tracerObject % index_algalChlorophyll, & + nt_bgc_DOC_out=tracerObject % index_DOCConc, & + nt_bgc_DON_out=tracerObject % index_DONConc, & + nt_bgc_DIC_out=tracerObject % index_DICConc, & + nt_zaero_out=tracerObject % index_verticalAerosolsConc, & + nt_bgc_DMSPp_out=tracerObject % index_DMSPpConc, & + nt_bgc_DMSPd_out=tracerObject % index_DMSPdConc, & + nt_bgc_Fed_out=tracerObject % index_dissolvedIronConc, & + nt_bgc_Fep_out=tracerObject % index_particulateIronConc, & + nt_zbgc_frac_out=tracerObject % index_mobileFraction, & + tr_bgc_Nit_in=config_use_nitrate, & + tr_bgc_Am_in=config_use_ammonium, & + tr_bgc_Sil_in=config_use_silicate, & + tr_bgc_DMS_in=config_use_DMS, & + tr_bgc_PON_in=config_use_nonreactive, & + tr_bgc_N_in=use_nitrogen, & + tr_bgc_C_in=config_use_carbon, & + tr_bgc_chl_in=config_use_chlorophyll, & + tr_bgc_DON_in=config_use_DON, & + tr_bgc_Fe_in=config_use_iron,& + tr_zaero_in=config_use_zaerosols, & + nlt_zaero_sw_out=tracerObject % index_verticalAerosolsConcShortwave, & + nlt_chl_sw_out=tracerObject % index_chlorophyllShortwave, & + nlt_bgc_N_out=tracerObject % index_algaeConcLayer, & + nlt_bgc_Nit_out=tracerObject % index_nitrateConcLayer, & + nlt_bgc_Am_out=tracerObject % index_ammoniumConcLayer, & + nlt_bgc_Sil_out=tracerObject % index_silicateConcLayer, & + nlt_bgc_DMS_out=tracerObject % index_DMSConcLayer, & + nlt_bgc_DMSPp_out=tracerObject % index_DMSPpConcLayer, & + nlt_bgc_DMSPd_out=tracerObject % index_DMSPdConcLayer, & + nlt_bgc_C_out=tracerObject % index_algalCarbonLayer, & + nlt_bgc_chl_out=tracerObject % index_algalChlorophyllLayer, & + nlt_bgc_DIC_out=tracerObject % index_DICConcLayer, & + nlt_bgc_DOC_out=tracerObject % index_DOCConcLayer, & + nlt_bgc_PON_out=tracerObject % index_nonreactiveConcLayer, & + nlt_bgc_DON_out=tracerObject % index_DONConcLayer, & + nlt_bgc_Fed_out=tracerObject % index_dissolvedIronConcLayer, & + nlt_bgc_Fep_out=tracerObject % index_particulateIronConcLayer, & + nlt_zaero_out=tracerObject % index_verticalAerosolsConcLayer, & + nt_bgc_hum_out=tracerObject % index_humicsConc, & + nlt_bgc_hum_out=tracerObject % index_humicsConcLayer, & + tr_bgc_hum_in=config_use_humics, & + skl_bgc_in=config_use_skeletal_biochemistry, & + z_tracers_in=config_use_vertical_tracers, & + dEdd_algae_in=config_use_shortwave_bioabsorption, & + solve_zbgc_in=config_use_vertical_biochemistry, & + bio_index_o_out=tracerObject % index_LayerIndexToDataArray, & + bio_index_out=tracerObject % index_LayerIndexToBioIndex) + + call icepack_init_zbgc() + ! check calculated tracer array size if (nTracers_temp /= tracerObject % nTracers) then call mpas_log_write(& From 60344fd6bf72c7f4e3701f6c46d2b31fe7be4741 Mon Sep 17 00:00:00 2001 From: dqwu Date: Fri, 3 May 2024 16:03:06 -0500 Subject: [PATCH 156/388] Simplifying PIO calls for interface restartvar in ELM This change optimizes the restartvar code in ELM with the following improvements: * Utilization of the ncid returned by subroutine ncd_defvar_bygrid, eliminating the need for calling PIO_inq_varid. * Introduction of additional optional arguments in the call to ncd_defvar_bygrid to internally set corresponding attributes. * Elimination of some redundant PIO_put_att calls that are already handled within ncd_defvar_bygrid. --- components/elm/src/utils/restUtilMod.F90.in | 189 ++++++++------------ 1 file changed, 75 insertions(+), 114 deletions(-) diff --git a/components/elm/src/utils/restUtilMod.F90.in b/components/elm/src/utils/restUtilMod.F90.in index 7bb9dd04093..47e3bc87a76 100644 --- a/components/elm/src/utils/restUtilMod.F90.in +++ b/components/elm/src/utils/restUtilMod.F90.in @@ -68,7 +68,6 @@ contains ! ! Local variables integer :: ivalue - type(var_desc_t) :: vardesc ! local vardesc integer :: status ! return error code integer :: varid integer :: lxtype ! local external type (in case logical variable) @@ -84,10 +83,10 @@ contains end if call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & - long_name=trim(long_name), units=units) - - status = PIO_inq_varid(ncid, trim(varname), vardesc) - varid = vardesc%varid + long_name=trim(long_name), units=units, comment=comment, & + fill_value=fill_value, missing_value=missing_value, & + ifill_value=ifill_value, imissing_value=imissing_value, & + varid=varid) if (trim(interpinic_flag) == 'interp') then status = PIO_put_att(ncid, varid, 'interpinic_flag', iflag_interp) @@ -99,36 +98,25 @@ contains status = PIO_put_att(ncid, varid, 'interpinic_flag_meanings', & "1=nearest neighbor, 2=copy directly, 3=skip") - if (present(comment)) then - call ncd_putatt(ncid, varid, 'comment', trim(comment)) - end if - if (present(units)) then - call ncd_putatt(ncid, varid, 'units', trim(units)) - end if - if (present(fill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', fill_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) + if (.not. present(fill_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) + end if end if - if (present(missing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', missing_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) + if (.not. present(missing_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) + end if end if - if (present(ifill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', ifill_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) + if (.not. present(ifill_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) + end if end if - if (present(imissing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', imissing_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) - end if - if ( xtype == ncd_log )then - status = PIO_put_att(ncid,varid,'flag_values', (/0, 1/) ) - status = PIO_put_att(ncid,varid,'flag_meanings', "FALSE TRUE" ) - status = PIO_put_att(ncid,varid,'valid_range', (/0, 1/) ) + if (.not. present(imissing_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) + end if end if else if (flag == 'read' .or. flag == 'write') then @@ -178,7 +166,6 @@ contains ! ! Local variables integer :: ivalue - type(var_desc_t) :: vardesc ! local vardesc integer :: status ! return error code integer :: varid integer :: lxtype ! local external type (in case logical variable) @@ -195,20 +182,23 @@ contains if (.not. present(dim1name)) then call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & - long_name=trim(long_name), units=units) + long_name=trim(long_name), units=units, comment=comment, fill_value=fill_Value, & + missing_value=missing_value, ifill_value=ifill_value, imissing_value=imissing_value, & + nvalid_range=nvalid_range, varid=varid) else if (.not. present(dim2name)) then call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & dim1name=trim(dim1name), & - long_name=trim(long_name), units=units) + long_name=trim(long_name), units=units, comment=comment, fill_value=fill_Value, & + missing_value=missing_value, ifill_value=ifill_value, imissing_value=imissing_value, & + nvalid_range=nvalid_range, varid=varid) else if (present(dim2name)) then call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & dim1name=trim(dim1name), dim2name=trim(dim2name), & - long_name=trim(long_name), units=units) + long_name=trim(long_name), units=units, comment=comment, fill_value=fill_Value, & + missing_value=missing_value, ifill_value=ifill_value, imissing_value=imissing_value, & + nvalid_range=nvalid_range, varid=varid) end if - status = PIO_inq_varid(ncid, trim(varname), vardesc) - varid = vardesc%varid - if (trim(interpinic_flag) == 'interp') then status = PIO_put_att(ncid, varid, 'interpinic_flag', iflag_interp) else if (trim(interpinic_flag) == 'copy') then @@ -219,40 +209,25 @@ contains status = PIO_put_att(ncid, varid, 'interpinic_flag_meanings', & "1=nearest neighbor, 2=copy directly, 3=skip") - if (present(comment)) then - call ncd_putatt(ncid, varid, 'comment', trim(comment)) + if (.not. present(fill_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) + end if end if - if (present(units)) then - call ncd_putatt(ncid, varid, 'units', trim(units)) + if (.not. present(missing_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) + end if end if - - if (present(fill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', fill_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) - end if - if (present(missing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', missing_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) - end if - if (present(ifill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', ifill_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) + if (.not. present(ifill_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) + end if end if - if (present(imissing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', imissing_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) - end if - if (present(nvalid_range)) then - status = PIO_put_att(ncid,varid,'valid_range', nvalid_range ) - end if - if ( xtype == ncd_log )then - status = PIO_put_att(ncid,varid,'flag_values', (/0, 1/) ) - status = PIO_put_att(ncid,varid,'flag_meanings', "FALSE TRUE" ) - status = PIO_put_att(ncid,varid,'valid_range', (/0, 1/) ) + if (.not. present(imissing_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) + end if end if else if (flag == 'read' .or. flag == 'write') then @@ -309,7 +284,6 @@ contains ! ! Local variables integer :: ivalue - type(var_desc_t) :: vardesc ! local vardesc integer :: status ! return error code integer :: varid ! returned var id integer :: lxtype ! local external type (in case logical variable) @@ -327,15 +301,16 @@ contains if (switchdim) then call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & dim1name=trim(dim2name), dim2name=trim(dim1name), & - long_name=trim(long_name), units=units) + long_name=trim(long_name), units=units, comment=comment, fill_value=fill_Value, & + missing_value=missing_value, ifill_value=ifill_value, imissing_value=imissing_value, & + nvalid_range=nvalid_range, varid=varid) else call ncd_defvar(ncid=ncid, varname=trim(varname), xtype=lxtype, & dim1name=trim(dim1name), dim2name=trim(dim2name), & - long_name=trim(long_name), units=units) + long_name=trim(long_name), units=units, comment=comment, fill_value=fill_Value, & + missing_value=missing_value, ifill_value=ifill_value, imissing_value=imissing_value, & + nvalid_range=nvalid_range, varid=varid) end if - status = PIO_inq_varid(ncid, trim(varname), vardesc) - - varid = vardesc%varid if (trim(interpinic_flag) == 'interp') then status = PIO_put_att(ncid, varid, 'interpinic_flag', iflag_interp) @@ -348,49 +323,35 @@ contains "1=>nearest_neighbor 2=>copy 3=>skip") if (switchdim) then - status = PIO_put_att(ncid, vardesc%varid, 'switchdim_flag', 1) + status = PIO_put_att(ncid, varid, 'switchdim_flag', 1) else - status = PIO_put_att(ncid, vardesc%varid, 'switchdim_flag', 0) + status = PIO_put_att(ncid, varid, 'switchdim_flag', 0) end if - status = PIO_put_att(ncid, vardesc%varid, 'switchdim_flag_values', (/0,1/)) - status = PIO_put_att(ncid, vardesc%varid, 'switchdim_flag_is_0', & + status = PIO_put_att(ncid, varid, 'switchdim_flag_values', (/0,1/)) + status = PIO_put_att(ncid, varid, 'switchdim_flag_is_0', & "1st and 2nd dims are same as model representation") - status = PIO_put_att(ncid, vardesc%varid, 'switchdim_flag_is_1', & + status = PIO_put_att(ncid, varid, 'switchdim_flag_is_1', & "1st and 2nd dims are switched from model representation") - if (present(comment)) then - call ncd_putatt(ncid, varid, 'comment', trim(comment)) - end if - if (present(units)) then - call ncd_putatt(ncid, varid, 'units', trim(units)) - end if - if (present(fill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', fill_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) - end if - if (present(missing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', missing_value, lxtype) - else if (lxtype == ncd_double) then - call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) - end if - if (present(ifill_value)) then - call ncd_putatt(ncid, varid, '_FillValue', ifill_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) - end if - if (present(imissing_value)) then - call ncd_putatt(ncid, varid, 'missing_value', imissing_value, lxtype) - else if (lxtype == ncd_int) then - call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) - end if - if (present(nvalid_range)) then - status = PIO_put_att(ncid,varid,'valid_range', nvalid_range ) - end if - if ( xtype == ncd_log )then - status = PIO_put_att(ncid,varid,'flag_values', (/0, 1/) ) - status = PIO_put_att(ncid,varid,'flag_meanings', "FALSE TRUE" ) - status = PIO_put_att(ncid,varid,'valid_range', (/0, 1/) ) + if (.not. present(fill_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, '_FillValue', spval, lxtype) + end if + end if + if (.not. present(missing_value)) then + if (lxtype == ncd_double) then + call ncd_putatt(ncid, varid, 'missing_value', spval, lxtype) + end if + end if + if (.not. present(ifill_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, '_FillValue', ispval, lxtype) + end if + end if + if (.not. present(imissing_value)) then + if (lxtype == ncd_int) then + call ncd_putatt(ncid, varid, 'missing_value', ispval, lxtype) + end if end if else From b7bac9e70d2d9b83eb7df2a49ee4db7419bcdf26 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 8 May 2024 11:40:49 -0700 Subject: [PATCH 157/388] misc fixes --- components/eam/src/physics/cam/phys_grid_ctem.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index 1f8172dd52c..acf91b97cfe 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -22,7 +22,7 @@ module phys_grid_ctem use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: begchunk, endchunk, pcols, pver use physics_types, only: physics_state -use cam_history, only: addfld, outfld +use cam_history, only: addfld, outfld, horiz_only use zonal_mean_mod,only: ZonalAverage_t, ZonalMean_t use physconst, only: pi use cam_logfile, only: iulog @@ -221,7 +221,7 @@ subroutine phys_grid_ctem_init if (.not.do_tem_diags) return - call addfld ('PSzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean surface pressure', gridname='ctem_zavg_phys' ) + call addfld ('PSzm',horiz_only, 'A','m s-1', 'Zonal-Mean surface pressure', gridname='ctem_zavg_phys' ) call addfld ('Uzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean zonal wind', gridname='ctem_zavg_phys' ) call addfld ('Vzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean meridional wind', gridname='ctem_zavg_phys' ) call addfld ('Wzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean vertical wind', gridname='ctem_zavg_phys' ) From 9e2efa27d5bcc13af37c44142ea59e6a45da8695 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 9 May 2024 11:20:55 -0700 Subject: [PATCH 158/388] remove mbarv from TEM output code --- components/eam/src/physics/cam/phys_grid_ctem.F90 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/eam/src/physics/cam/phys_grid_ctem.F90 b/components/eam/src/physics/cam/phys_grid_ctem.F90 index acf91b97cfe..86d11922079 100644 --- a/components/eam/src/physics/cam/phys_grid_ctem.F90 +++ b/components/eam/src/physics/cam/phys_grid_ctem.F90 @@ -282,10 +282,6 @@ subroutine phys_grid_ctem_diags(phys_state) real(r8) :: wza(nzalat,pver) real(r8) :: thza(nzalat,pver) - ! In CESM/WACCM the variable mbarv is provided by the "air_composition" - ! module, which is not in E3SM, so we just use a rough approximation - real(r8) :: mbarv = 28.97 ! molecular weight of dry air (g/mol) - if (.not.do_calc()) return do lchnk = begchunk,endchunk From 9af6e77cc7cdb76c7b46bee3e445a3cc2cd0f1d1 Mon Sep 17 00:00:00 2001 From: zyuying Date: Thu, 9 May 2024 16:30:46 -0700 Subject: [PATCH 159/388] Add files via upload --- components/eam/src/physics/cosp2/Cosp.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/src/physics/cosp2/Cosp.cmake b/components/eam/src/physics/cosp2/Cosp.cmake index 922ac409399..aca87f093b7 100644 --- a/components/eam/src/physics/cosp2/Cosp.cmake +++ b/components/eam/src/physics/cosp2/Cosp.cmake @@ -5,7 +5,7 @@ set(COSP_SOURCES eam/src/physics/cosp2/cosp_kinds.F90 eam/src/physics/cosp2/external/src/cosp_constants.F90 eam/src/physics/cosp2/external/src/simulator/cosp_cloudsat_interface.F90 - eam/src/physics/cosp2/external/src/cosp_config.F90 + eam/src/physics/cosp2/local/cosp_config.F90 eam/src/physics/cosp2/local/cosp.F90 eam/src/physics/cosp2/external/src/cosp_stats.F90 eam/src/physics/cosp2/external/src/simulator/quickbeam/quickbeam.F90 @@ -19,7 +19,7 @@ set(COSP_SOURCES eam/src/physics/cosp2/external/src/simulator/cosp_misr_interface.F90 eam/src/physics/cosp2/external/src/simulator/MISR_simulator/MISR_simulator.F90 eam/src/physics/cosp2/external/src/simulator/cosp_modis_interface.F90 - eam/src/physics/cosp2/external/src/simulator/MODIS_simulator/modis_simulator.F90 + eam/src/physics/cosp2/local/modis_simulator.F90 eam/src/physics/cosp2/external/src/simulator/cosp_rttov_interfaceSTUB.F90 eam/src/physics/cosp2/external/src/simulator/rttov/cosp_rttovSTUB.F90 eam/src/physics/cosp2/external/src/simulator/cosp_parasol_interface.F90 From 2e60cd09118fd0150d9e654088adcc9012c624af Mon Sep 17 00:00:00 2001 From: zyuying Date: Thu, 9 May 2024 16:32:10 -0700 Subject: [PATCH 160/388] Add files via upload --- .../eam/src/physics/cosp2/local/cosp.F90 | 323 +++++- .../src/physics/cosp2/local/cosp_config.F90 | 502 +++++++++ .../physics/cosp2/local/modis_simulator.F90 | 959 ++++++++++++++++++ 3 files changed, 1753 insertions(+), 31 deletions(-) create mode 100644 components/eam/src/physics/cosp2/local/cosp_config.F90 create mode 100644 components/eam/src/physics/cosp2/local/modis_simulator.F90 diff --git a/components/eam/src/physics/cosp2/local/cosp.F90 b/components/eam/src/physics/cosp2/local/cosp.F90 index 8ecc3031e3e..129678ce316 100644 --- a/components/eam/src/physics/cosp2/local/cosp.F90 +++ b/components/eam/src/physics/cosp2/local/cosp.F90 @@ -30,6 +30,8 @@ ! May 2015- D. Swales - Original version ! Mar 2018- R. Guzman - Added OPAQ diagnostics and GLID simulator ! Apr 2018- R. Guzman - Added ATLID simulator +! Nov 2018- T. Michibata - Added CloudSat+MODIS Warmrain Diagnostics +! Mar 2024- C. Wall - Added MODIS joint-histogram diagnostics ! ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -39,9 +41,12 @@ MODULE MOD_COSP USE MOD_COSP_CONFIG, ONLY: R_UNDEF,PARASOL_NREFL,LIDAR_NCAT,LIDAR_NTYPE, SR_BINS,& N_HYDRO,RTTOV_MAX_CHANNELS,numMISRHgtBins, & cloudsat_DBZE_BINS,LIDAR_NTEMP,calipso_histBsct,& - use_vgrid,Nlvgrid,vgrid_zu,vgrid_zl,vgrid_z, & + use_vgrid,Nlvgrid,vgrid_zu,vgrid_zl,vgrid_z,dz, & + WR_NREGIME, CFODD_NCLASS, & + CFODD_NDBZE, CFODD_NICOD, & numMODISTauBins,numMODISPresBins, & numMODISReffIceBins,numMODISReffLiqBins, & + numMODISLWPBins,numMODISIWPBins, & numISCCPTauBins,numISCCPPresBins,numMISRTauBins,& ntau,modis_histTau,tau_binBounds, & modis_histTauEdges,tau_binEdges,nCloudsatPrecipClass,& @@ -63,7 +68,8 @@ MODULE MOD_COSP USE MOD_MODIS_SIM, ONLY: modis_subcolumn, modis_column USE MOD_PARASOL, ONLY: parasol_subcolumn, parasol_column use mod_cosp_rttov, ONLY: rttov_column - USE MOD_COSP_STATS, ONLY: COSP_LIDAR_ONLY_CLOUD,COSP_CHANGE_VERTICAL_GRID + USE MOD_COSP_STATS, ONLY: COSP_LIDAR_ONLY_CLOUD,COSP_CHANGE_VERTICAL_GRID, & + COSP_DIAG_WARMRAIN IMPLICIT NONE @@ -86,8 +92,10 @@ MODULE MOD_COSP pfull, & ! Pressure (Pa) phalf, & ! Pressure at half-levels (Pa) qv, & ! Specific humidity (kg/kg) - hgt_matrix, & ! Height of hydrometeors (km) - hgt_matrix_half ! Height of hydrometeors at half levels (km) + hgt_matrix, & ! Height of atmosphere layer (km) + hgt_matrix_half ! Height of bottom interface of atm layer(km) + ! First level contains the bottom of the top layer. + ! Last level contains the bottom of the surface layer. real(wp),allocatable,dimension(:) :: & land, & ! Land/Sea mask (0-1) @@ -284,10 +292,22 @@ MODULE MOD_COSP modis_Optical_Thickness_vs_ReffICE => null(), & ! Tau/ReffICE joint histogram modis_Optical_Thickness_vs_ReffLIQ => null() ! Tau/ReffLIQ joint histogram + real(wp),pointer,dimension(:,:,:) :: & + modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq => null(), & ! Tau/Pressure Liq joint histogram + modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice => null(), & ! Tau/Pressure Ice joint histogram + modis_LWP_vs_ReffLIQ => null(), & ! LWP/ReffLIQ joint histogram + modis_IWP_vs_ReffICE => null() ! IWP/ReffICE joint histogram + ! RTTOV outputs real(wp),pointer :: & rttov_tbs(:,:) => null() ! Brightness Temperature + ! Joint CloudSat+MODIS simulators outputs + real(wp),dimension(:,:,:,:),pointer :: & + cfodd_ntotal => null() ! # of CFODD (Npoints,CFODD_NDBZE,CFODD_NICOD,CFODD_NCLASS) + real(wp),dimension(:,:), pointer :: & + wr_occfreq_ntotal => null() ! # of nonprecip/drizzle/precip (Npoints,WR_NREGIME) + end type cosp_outputs CONTAINS @@ -318,6 +338,7 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) ! Local variables integer :: & i,icol,ij,ik,nError + integer :: k integer,target :: & Npoints logical :: & @@ -340,15 +361,16 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) Lmodis_column, & ! On/Off switch for column MODIS simulator Lrttov_column, & ! On/Off switch for column RTTOV simulator (not used) Lradar_lidar_tcc, & ! On/Off switch from joint Calipso/Cloudsat product - Lcloudsat_tcc, & ! - Lcloudsat_tcc2, & ! - Llidar_only_freq_cloud ! On/Off switch from joint Calipso/Cloudsat product + Lcloudsat_tcc, & ! + Lcloudsat_tcc2, & ! + Llidar_only_freq_cloud, & ! On/Off switch from joint Calipso/Cloudsat product + Lcloudsat_modis_wr ! On/Off switch from joint CloudSat/MODIS warm rain product logical :: & ok_lidar_cfad = .false., & ok_lidar_cfad_grLidar532 = .false., & ok_lidar_cfad_atlid = .false., & lrttov_cleanUp = .false. - + integer, dimension(:,:),allocatable :: & modisRetrievedPhase,isccpLEVMATCH real(wp), dimension(:), allocatable :: & @@ -365,13 +387,21 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) grLidar532_beta_mol,atlid_beta_mol REAL(WP), dimension(:,:,:),allocatable :: & modisJointHistogram,modisJointHistogramIce,modisJointHistogramLiq, & + modisJointHistogram_CtpCodLiq,modisJointHistogram_CtpCodIce, & + modisJointHistogram_LwpRefLiq,modisJointHistogram_IwpRefIce, & calipso_beta_tot,calipso_betaperp_tot, cloudsatDBZe,parasolPix_refl, & grLidar532_beta_tot,atlid_beta_tot,cloudsatZe_non real(wp),dimension(:),allocatable,target :: & out1D_1,out1D_2,out1D_3,out1D_4,out1D_5,out1D_6,out1D_7,out1D_8, & out1D_9,out1D_10,out1D_11,out1D_12 real(wp),dimension(:,:,:),allocatable :: & - betamol_in,betamoli,pnormi,ze_toti,ze_noni + betamol_in,betamoli,pnormi,ze_toti + real(wp),dimension(:,:,:),allocatable :: & + t_in,tempI,frac_outI ! subscript "I": vertical interpolation (use_vgrid=.true.) + real(wp), allocatable :: & + zlev (:,:), & ! altitude (used only when use_vgrid=.true.) + cfodd_ntotal (:,:,:,:), & ! # of total samples for CFODD (Npoints,CFODD_NDBZE,CFODD_NICOD,CFODD_NCLASS) + wr_occfreq_ntotal(:,:) ! # of warm-rain (nonprecip/drizzle/precip) (Npoints,WR_NREGIME) ! Initialize error reporting for output cosp_simulator(:)='' @@ -417,6 +447,7 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) Llidar_only_freq_cloud = .false. Lcloudsat_tcc = .false. Lcloudsat_tcc2 = .false. + Lcloudsat_modis_wr = .false. ! CLOUDSAT subcolumn if (associated(cospOUT%cloudsat_Ze_tot)) Lcloudsat_subcolumn = .true. @@ -478,9 +509,7 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) Lrttov_column = .true. ! Set flag to deallocate rttov types (only done on final call to simulator) - if (associated(cospOUT%isccp_meantb)) then - if (size(cospOUT%isccp_meantb) .eq. stop_idx) lrttov_cleanUp = .true. - endif + if (size(cospOUT%isccp_meantb) .eq. stop_idx) lrttov_cleanUp = .true. ! ISCCP column if (associated(cospOUT%isccp_fq) .or. & @@ -582,6 +611,15 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) Lcloudsat_tcc2 = .true. endif + ! CloudSat+MODIS joint simulator product + if ( associated(cospOUT%cfodd_ntotal) .or. associated(cospOUT%wr_occfreq_ntotal) ) then + Lmodis_column = .true. + Lmodis_subcolumn = .true. + Lcloudsat_column = .true. + Lcloudsat_subcolumn = .true. + Lcloudsat_modis_wr = .true. ! WR: warm rain product + endif + !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ! 2b) Error Checking ! Enforce bounds on input fields. If input field is out-of-bounds, report error @@ -592,8 +630,8 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) Lcloudsat_subcolumn, Lcloudsat_column, Lcalipso_subcolumn, Lcalipso_column, & Latlid_subcolumn, Latlid_column, LgrLidar532_subcolumn, LgrLidar532_column, & Lrttov_subcolumn, Lrttov_column, Lparasol_subcolumn, Lparasol_column, & - Lradar_lidar_tcc, Llidar_only_freq_cloud, Lcloudsat_tcc,Lcloudsat_tcc2, cospOUT,& - cosp_simulator, nError) + Lradar_lidar_tcc, Llidar_only_freq_cloud, Lcloudsat_tcc,Lcloudsat_tcc2, & + Lcloudsat_modis_wr, cospOUT, cosp_simulator, nError) !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ! 3) Populate instrument simulator inputs @@ -708,7 +746,7 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) rttovIN%n2o => cospgridIN%n2o rttovIN%co => cospgridIN%co rttovIN%surfem => cospgridIN%emis_sfc - rttovIN%h_surf => cospgridIN%hgt_matrix_half(:,cospIN%Nlevels+1) + rttovIN%h_surf => cospgridIN%hgt_matrix_half(:,cospIN%Nlevels) rttovIN%u_surf => cospgridIN%u_sfc rttovIN%v_surf => cospgridIN%v_sfc rttovIN%t_skin => cospgridIN%skt @@ -1064,7 +1102,7 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) ok_lidar_cfad=.true. call lidar_column(calipsoIN%Npoints, calipsoIN%Ncolumns, calipsoIN%Nlevels, & Nlvgrid, SR_BINS, LIDAR_NTYPE, 'calipso',calipso_beta_tot(:,:,:), calipso_beta_mol(:,:),& - cospgridIN%phalf(:,2:calipsoIN%Nlevels+1),cospgridIN%hgt_matrix, & + cospgridIN%phalf(:,2:calipsoIN%Nlevels+1),cospgridIN%hgt_matrix, & cospgridIN%hgt_matrix_half, vgrid_z(:), ok_lidar_cfad, LIDAR_NCAT, & cospOUT%calipso_cfad_sr(ij:ik,:,:), cospOUT%calipso_lidarcld(ij:ik,:), & cospOUT%calipso_cldlayer(ij:ik,:), & @@ -1281,7 +1319,12 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) modisMeanIceWaterPath(modisIN%nSunlit), & modisJointHistogram(modisIN%nSunlit,numMODISTauBins,numMODISPresBins),& modisJointHistogramIce(modisIN%nSunlit,numModisTauBins,numMODISReffIceBins),& - modisJointHistogramLiq(modisIN%nSunlit,numModisTauBins,numMODISReffLiqBins)) + modisJointHistogramLiq(modisIN%nSunlit,numModisTauBins,numMODISReffLiqBins),& + modisJointHistogram_CtpCodLiq(modisIN%nSunlit,numMODISTauBins,numMODISPresBins),& + modisJointHistogram_CtpCodIce(modisIN%nSunlit,numMODISTauBins,numMODISPresBins),& + modisJointHistogram_LwpRefLiq(modisIN%nSunlit,numMODISLWPBins,numMODISReffLiqBins), & + modisJointHistogram_IwpRefIce(modisIN%nSunlit,numMODISIWPBins,numMODISReffIceBins) & + ) ! Call simulator call modis_column(modisIN%nSunlit, modisIN%Ncolumns,modisRetrievedPhase, & modisRetrievedCloudTopPressure,modisRetrievedTau, & @@ -1292,7 +1335,12 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) modisMeanSizeLiquid, modisMeanSizeIce, & modisMeanCloudTopPressure, modisMeanLiquidWaterPath, & modisMeanIceWaterPath, modisJointHistogram, & - modisJointHistogramIce,modisJointHistogramLiq) + modisJointHistogramIce,modisJointHistogramLiq, & + modisJointHistogram_CtpCodLiq, & + modisJointHistogram_CtpCodIce, & + modisJointHistogram_LwpRefLiq, & + modisJointHistogram_IwpRefIce & + ) ! Store data (if requested) if (associated(cospOUT%modis_Cloud_Fraction_Total_Mean)) then cospOUT%modis_Cloud_Fraction_Total_Mean(ij+int(modisIN%sunlit(:))-1) = & @@ -1369,6 +1417,30 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(ij:ik,:,:) = & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(ij:ik,:,numMODISPresBins:1:-1) endif + + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) then + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(ij+ & + int(modisIN%sunlit(:))-1, 1:numModisTauBins, :) = modisJointHistogram_CtpCodLiq(:, :, :) + ! Reorder pressure bins in joint histogram to go from surface to TOA + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(ij:ik,:,:) = & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(ij:ik,:,numMODISPresBins:1:-1) + endif + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) then + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(ij+ & + int(modisIN%sunlit(:))-1, 1:numModisTauBins, :) = modisJointHistogram_CtpCodIce(:, :, :) + ! Reorder pressure bins in joint histogram to go from surface to TOA + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(ij:ik,:,:) = & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(ij:ik,:,numMODISPresBins:1:-1) + endif + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) then + cospOUT%modis_LWP_vs_ReffLIQ(ij+int(modisIN%sunlit(:))-1, 1:numMODISLWPBins,:) = & + modisJointHistogram_LwpRefLiq(:,:,:) + endif + if (associated(cospOUT%modis_IWP_vs_ReffICE)) then + cospOUT%modis_IWP_vs_ReffICE(ij+int(modisIN%sunlit(:))-1, 1:numMODISIWPBins,:) = & + modisJointHistogram_IwpRefIce(:,:,:) + endif + if (associated(cospOUT%modis_Optical_Thickness_vs_ReffIce)) then cospOUT%modis_Optical_Thickness_vs_ReffIce(ij+int(modisIN%sunlit(:))-1, 1:numMODISTauBins,:) = & modisJointHistogramIce(:,:,:) @@ -1479,6 +1551,10 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) if (allocated(modisMeanLiquidWaterPath)) deallocate(modisMeanLiquidWaterPath) if (allocated(modisMeanIceWaterPath)) deallocate(modisMeanIceWaterPath) if (allocated(modisJointHistogram)) deallocate(modisJointHistogram) + if (allocated(modisJointHistogram_CtpCodLiq)) deallocate(modisJointHistogram_CtpCodLiq) + if (allocated(modisJointHistogram_CtpCodIce)) deallocate(modisJointHistogram_CtpCodIce) + if (allocated(modisJointHistogram_LwpRefLiq)) deallocate(modisJointHistogram_LwpRefLiq) + if (allocated(modisJointHistogram_IwpRefIce)) deallocate(modisJointHistogram_IwpRefIce) if (allocated(modisJointHistogramIce)) deallocate(modisJointHistogramIce) if (allocated(modisJointHistogramLiq)) deallocate(modisJointHistogramLiq) if (allocated(isccp_boxttop)) deallocate(isccp_boxttop) @@ -1572,6 +1648,85 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) endif endif + ! CloudSat/MODIS joint products (CFODDs and Occurrence Frequency of Warm Clouds) + if (Lcloudsat_modis_wr) then + allocate( cfodd_ntotal(cloudsatIN%Npoints, CFODD_NDBZE, CFODD_NICOD, CFODD_NCLASS) ) + allocate( wr_occfreq_ntotal(cloudsatIN%Npoints, WR_NREGIME) ) + + if ( use_vgrid ) then + !! interporation for fixed vertical grid: + allocate( zlev(cloudsatIN%Npoints,Nlvgrid), & + t_in(cloudsatIN%Npoints,1,cloudsatIN%Nlevels), & + tempI(cloudsatIN%Npoints,1,Nlvgrid), & + Ze_totI(cloudsatIN%Npoints,cloudsatIN%Ncolumns,Nlvgrid), & + frac_outI(cloudsatIN%Npoints,cloudsatIN%Ncolumns,Nlvgrid) ) + do k = 1, Nlvgrid + zlev(:,k) = vgrid_zu(k) + enddo + t_in(:,1,:) = cospgridIN%at(:,:) + call cosp_change_vertical_grid ( & + cloudsatIN%Npoints, 1, cloudsatIN%Nlevels, & + cospgridIN%hgt_matrix(:,cloudsatIN%Nlevels:1:-1), & + cospgridIN%hgt_matrix_half(:,cloudsatIN%Nlevels:1:-1), & + t_in(:,:,cloudsatIN%Nlevels:1:-1), Nlvgrid, & + vgrid_zl(Nlvgrid:1:-1), vgrid_zu(Nlvgrid:1:-1), & + tempI(:,:,Nlvgrid:1:-1) ) + call cosp_change_vertical_grid ( & + cloudsatIN%Npoints, cloudsatIN%Ncolumns, cloudsatIN%Nlevels, & + cospgridIN%hgt_matrix(:,cloudsatIN%Nlevels:1:-1), & + cospgridIN%hgt_matrix_half(:,cloudsatIN%Nlevels:1:-1), & + cloudsatDBZe(:,:,cloudsatIN%Nlevels:1:-1), Nlvgrid, & + vgrid_zl(Nlvgrid:1:-1), vgrid_zu(Nlvgrid:1:-1), & + Ze_totI(:,:,Nlvgrid:1:-1), log_units=.true. ) + call cosp_change_vertical_grid ( & + cloudsatIN%Npoints, cloudsatIN%Ncolumns, cloudsatIN%Nlevels, & + cospgridIN%hgt_matrix(:,cloudsatIN%Nlevels:1:-1), & + cospgridIN%hgt_matrix_half(:,cloudsatIN%Nlevels:1:-1), & + cospIN%frac_out(:,:,cloudsatIN%Nlevels:1:-1), Nlvgrid, & + vgrid_zl(Nlvgrid:1:-1), vgrid_zu(Nlvgrid:1:-1), & + frac_outI(:,:,Nlvgrid:1:-1) ) + call cosp_diag_warmrain( & + cloudsatIN%Npoints, cloudsatIN%Ncolumns, Nlvgrid, & !! in + tempI, zlev, & !! in + cospOUT%modis_Liquid_Water_Path_Mean, & !! in + cospOUT%modis_Optical_Thickness_Water_Mean, & !! in + cospOUT%modis_Cloud_Particle_Size_Water_Mean, & !! in + cospOUT%modis_Cloud_Fraction_Water_Mean, & !! in + cospOUT%modis_Ice_Water_Path_Mean, & !! in + cospOUT%modis_Optical_Thickness_Ice_Mean, & !! in + cospOUT%modis_Cloud_Particle_Size_Ice_Mean, & !! in + cospOUT%modis_Cloud_Fraction_Ice_Mean, & !! in + frac_outI, & !! in + Ze_totI, & !! in + cfodd_ntotal, wr_occfreq_ntotal ) !! inout + deallocate( zlev, t_in, tempI, frac_outI, Ze_totI ) + else ! do not use vgrid interporation ---------------------------------------! + !! original model grid + call cosp_diag_warmrain( & + cloudsatIN%Npoints, cloudsatIN%Ncolumns, cospIN%Nlevels, & !! in + cospgridIN%at, cospgridIN%hgt_matrix, & !! in + cospOUT%modis_Liquid_Water_Path_Mean, & !! in + cospOUT%modis_Optical_Thickness_Water_Mean, & !! in + cospOUT%modis_Cloud_Particle_Size_Water_Mean, & !! in + cospOUT%modis_Cloud_Fraction_Water_Mean, & !! in + cospOUT%modis_Ice_Water_Path_Mean, & !! in + cospOUT%modis_Optical_Thickness_Ice_Mean, & !! in + cospOUT%modis_Cloud_Particle_Size_Ice_Mean, & !! in + cospOUT%modis_Cloud_Fraction_Ice_Mean, & !! in + cospIN%frac_out, & !! in + cloudsatDBZe, & !! in + cfodd_ntotal, wr_occfreq_ntotal ) !! inout + endif !! use_vgrid or not + + ! Store, when necessary + if ( associated(cospOUT%cfodd_ntotal) ) then + cospOUT%cfodd_ntotal(ij:ik,:,:,:) = cfodd_ntotal + endif + if ( associated(cospOUT%wr_occfreq_ntotal) ) then + cospOUT%wr_occfreq_ntotal(ij:ik,:) = wr_occfreq_ntotal + endif + endif + !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ! 7) Cleanup !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1633,6 +1788,8 @@ function COSP_SIMULATOR(cospIN,cospgridIN,cospOUT,start_idx,stop_idx,debug) if (allocated(radar_lidar_tcc)) deallocate(radar_lidar_tcc) if (allocated(cloudsat_tcc)) deallocate(cloudsat_tcc) if (allocated(cloudsat_tcc2)) deallocate(cloudsat_tcc2) + if (allocated(cfodd_ntotal)) deallocate(cfodd_ntotal) + if (allocated(wr_occfreq_ntotal)) deallocate(wr_occfreq_ntotal) end function COSP_SIMULATOR ! ###################################################################################### @@ -1684,7 +1841,7 @@ SUBROUTINE COSP_INIT(Lisccp, Lmodis, Lmisr, Lcloudsat, Lcalipso, LgrLidar532, La if (use_vgrid) then Nlvgrid = Nvgrid - allocate(vgrid_zl(Nlvgrid),vgrid_zu(Nlvgrid),vgrid_z(Nlvgrid)) + allocate(vgrid_zl(Nlvgrid),vgrid_zu(Nlvgrid),vgrid_z(Nlvgrid),dz(Nlvgrid)) ! CloudSat grid requested if (luseCSATvgrid) zstep = 480._wp ! Other grid requested. Constant vertical spacing with top at 20 km @@ -1694,9 +1851,14 @@ SUBROUTINE COSP_INIT(Lisccp, Lmodis, Lmisr, Lcloudsat, Lcalipso, LgrLidar532, La vgrid_zu(Nlvgrid-i+1) = i*zstep enddo vgrid_z = (vgrid_zl+vgrid_zu)/2._wp + dz = zstep else Nlvgrid = Nlevels - allocate(vgrid_zl(Nlvgrid),vgrid_zu(Nlvgrid),vgrid_z(Nlvgrid)) + allocate(vgrid_zl(Nlvgrid),vgrid_zu(Nlvgrid),vgrid_z(Nlvgrid),dz(Nlvgrid)) + vgrid_zl = 0._wp + vgrid_zu = 0._wp + vgrid_z = 0._wp + dz = 0._wp endif ! Initialize simulators @@ -1719,7 +1881,7 @@ END SUBROUTINE COSP_INIT ! SUBROUTINE cosp_cleanUp !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% subroutine cosp_cleanUp() - deallocate(vgrid_zl,vgrid_zu,vgrid_z) + deallocate(vgrid_zl,vgrid_zu,vgrid_z,dz) end subroutine cosp_cleanUp !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1728,9 +1890,10 @@ end subroutine cosp_cleanUp subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, & Lmisr_subcolumn, Lmisr_column, Lmodis_subcolumn, Lmodis_column, Lcloudsat_subcolumn, & Lcloudsat_column, Lcalipso_subcolumn, Lcalipso_column, Latlid_subcolumn, & - Latlid_column, LgrLidar532_subcolumn, LgrLidar532_column, Lrttov_subcolumn, & + Latlid_column, LgrLidar532_subcolumn, LgrLidar532_column, Lrttov_subcolumn, & Lrttov_column, Lparasol_subcolumn, Lparasol_column, Lradar_lidar_tcc, & - Llidar_only_freq_cloud, Lcloudsat_tcc, Lcloudsat_tcc2, cospOUT, errorMessage, nError) + Llidar_only_freq_cloud, Lcloudsat_tcc, Lcloudsat_tcc2, Lcloudsat_modis_wr, & + cospOUT, errorMessage, nError) ! Inputs type(cosp_column_inputs),intent(in) :: & @@ -1761,14 +1924,14 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Lcloudsat_tcc, & ! Lcloudsat_tcc2, & ! Lradar_lidar_tcc, & ! On/Off switch for joint Calipso/Cloudsat product - Llidar_only_freq_cloud ! On/Off switch for joint Calipso/Cloudsat product + Llidar_only_freq_cloud, & ! On/Off switch for joint Calipso/Cloudsat product + Lcloudsat_modis_wr ! On/Off switch for joint CloudSat/MODIS warm rain product type(cosp_outputs),intent(inout) :: & cospOUT ! COSP Outputs character(len=256),dimension(100) :: errorMessage integer,intent(out) :: nError ! Local variables - character(len=100) :: parasolErrorMessage logical :: alloc_status nError = 0 @@ -2080,6 +2243,11 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, errorMessage(nError) = 'ERROR: COSP input variable (Calipso Lidar simulator): cospgridIN%at has not been allocated' alloc_status = .false. endif + if (.not. allocated(cospgridIN%surfelev)) then + nError=nError+1 + errorMessage(nError) = 'ERROR: COSP input variable (Calipso Lidar simulator): cospgridIN%surfelev has not been allocated' + alloc_status = .false. + endif if (.not. allocated(cospgridIN%phalf)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable (Calipso Lidar simulator): cospgridIN%phalf has not been allocated' @@ -2173,6 +2341,12 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, ' cospgridIN%hgt_matrix has not been allocated' alloc_status = .false. endif + if (.not. allocated(cospgridIN%surfelev)) then + nError=nError+1 + errorMessage(nError) = 'ERROR: COSP input variable (Cloudsat radar simulator):'//& + ' cospgridIN%surfelev has not been allocated' + alloc_status = .false. + endif if (.not. alloc_status) then Lcloudsat_subcolumn = .false. Lcloudsat_column = .false. @@ -2195,6 +2369,11 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. if (associated(cospOUT%lidar_only_freq_cloud)) cospOUT%lidar_only_freq_cloud(:,:) = R_UNDEF endif + if (Lcloudsat_modis_wr) then + Lcloudsat_modis_wr = .false. + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF + endif endif ! Cloudsat column simulator requires additional inputs not required by the subcolumn simulator. @@ -2225,6 +2404,11 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. if (associated(cospOUT%lidar_only_freq_cloud)) cospOUT%lidar_only_freq_cloud(:,:) = R_UNDEF endif + if (Lcloudsat_modis_wr) then + Lcloudsat_modis_wr = .false. + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF + endif endif endif @@ -2295,10 +2479,24 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & cospOUT%modis_Optical_Thickness_vs_ReffLIQ(:,:,:) = R_UNDEF + ! Also, turn-off joint-products + if (Lcloudsat_modis_wr) then + Lcloudsat_modis_wr = .false. + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF + endif endif endif @@ -2427,7 +2625,8 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, ! an undefined value (set in cosp_config.f90) and if necessary, that simulator ! is turned off. !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - if (any([Lisccp_subcolumn, Lisccp_column, Lmisr_subcolumn, Lmisr_column, Lmodis_subcolumn, Lmodis_column])) then + if (any([Lisccp_subcolumn, Lisccp_column, Lmisr_subcolumn, Lmisr_column, & + Lmodis_subcolumn, Lmodis_column, Lcloudsat_modis_wr])) then if (any(cospgridIN%sunlit .lt. 0)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable: cospgridIN%sunlit contains values out of range (0 or 1)' @@ -2437,6 +2636,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Lmisr_column = .false. Lmodis_subcolumn = .false. Lmodis_column = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%isccp_totalcldarea)) cospOUT%isccp_totalcldarea(:) = R_UNDEF if (associated(cospOUT%isccp_meantb)) cospOUT%isccp_meantb(:) = R_UNDEF if (associated(cospOUT%isccp_meantbclr)) cospOUT%isccp_meantbclr(:) = R_UNDEF @@ -2486,16 +2686,26 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & cospOUT%modis_Optical_Thickness_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif endif if (any([Lisccp_subcolumn, Lisccp_column, Lmisr_subcolumn, Lmisr_column, Lrttov_column,& Lcalipso_column, Lcloudsat_column, Lradar_lidar_tcc,Llidar_only_freq_cloud, & - Lcloudsat_tcc, Lcloudsat_tcc2])) then + Lcloudsat_tcc, Lcloudsat_tcc2, Lcloudsat_modis_wr])) then if (any(cospgridIN%at .lt. 0)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable: cospgridIN%at contains values out of range (at<0), expected units (K)' @@ -2510,6 +2720,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. Lcloudsat_tcc = .false. Lcloudsat_tcc2 = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%rttov_tbs)) cospOUT%rttov_tbs(:,:) = R_UNDEF if (associated(cospOUT%isccp_totalcldarea)) cospOUT%isccp_totalcldarea(:) = R_UNDEF if (associated(cospOUT%isccp_meantb)) cospOUT%isccp_meantb(:) = R_UNDEF @@ -2541,6 +2752,8 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, if (associated(cospOUT%radar_lidar_tcc)) cospOUT%radar_lidar_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc)) cospOUT%cloudsat_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc2)) cospOUT%cloudsat_tcc2(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif endif if (any([Lisccp_subcolumn, Lisccp_column, Lrttov_column])) then @@ -2621,6 +2834,14 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & @@ -2665,7 +2886,8 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, endif endif if (any([Lmisr_subcolumn,Lmisr_column,Lcloudsat_subcolumn,Lcloudsat_column,Lcalipso_column,Lradar_lidar_tcc,& - Llidar_only_freq_cloud,LgrLidar532_column,Latlid_column,Lcloudsat_tcc, Lcloudsat_tcc2])) then + Llidar_only_freq_cloud,LgrLidar532_column,Latlid_column,Lcloudsat_tcc, Lcloudsat_tcc2, & + Lcloudsat_modis_wr])) then if (any(cospgridIN%hgt_matrix .lt. -300)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable: cospgridIN%hgt_matrix contains values out of range' @@ -2680,6 +2902,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Lcloudsat_tcc2 = .false. Latlid_column = .false. LgrLidar532_column = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%misr_fq)) cospOUT%misr_fq(:,:,:) = R_UNDEF if (associated(cospOUT%misr_dist_model_layertops)) cospOUT%misr_dist_model_layertops(:,:) = R_UNDEF if (associated(cospOUT%misr_meanztop)) cospOUT%misr_meanztop(:) = R_UNDEF @@ -2708,10 +2931,12 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, if (associated(cospOUT%calipso_cldtypemeanz)) cospOUT%calipso_cldtypemeanz(:,:) = R_UNDEF if (associated(cospOUT%calipso_cldtypemeanzse)) cospOUT%calipso_cldtypemeanzse(:,:) = R_UNDEF if (associated(cospOUT%calipso_cldthinemis)) cospOUT%calipso_cldthinemis(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif endif if (any([Lrttov_column,Lcloudsat_column,Lcalipso_column,Lradar_lidar_tcc,Llidar_only_freq_cloud, & - LgrLidar532_column, Latlid_column, Lcloudsat_tcc, Lcloudsat_tcc2])) then + LgrLidar532_column, Latlid_column, Lcloudsat_tcc, Lcloudsat_tcc2, Lcloudsat_modis_wr])) then if (any(cospgridIN%hgt_matrix_half .lt. -300)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable: cospgridIN%hgt_matrix_half contains values out of range' @@ -2724,6 +2949,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Lcloudsat_tcc2 = .false. Latlid_column = .false. LgrLidar532_column = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%rttov_tbs)) cospOUT%rttov_tbs(:,:) = R_UNDEF if (associated(cospOUT%calipso_cfad_sr)) cospOUT%calipso_cfad_sr(:,:,:) = R_UNDEF if (associated(cospOUT%calipso_lidarcld)) cospOUT%calipso_lidarcld(:,:) = R_UNDEF @@ -2748,6 +2974,8 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, if (associated(cospOUT%calipso_cldtypemeanz)) cospOUT%calipso_cldtypemeanz(:,:) = R_UNDEF if (associated(cospOUT%calipso_cldtypemeanzse)) cospOUT%calipso_cldtypemeanzse(:,:) = R_UNDEF if (associated(cospOUT%calipso_cldthinemis)) cospOUT%calipso_cldthinemis(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif endif if (any([Lrttov_column,Lcalipso_column,Lparasol_column])) then @@ -2934,6 +3162,14 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & @@ -2999,6 +3235,14 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & @@ -3045,6 +3289,14 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, cospOUT%modis_Ice_Water_Path_Mean(:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure)) & cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) & + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_LWP_vs_ReffLIQ)) & + cospOUT%modis_LWP_vs_ReffLIQ(:,:,:) = R_UNDEF + if (associated(cospOUT%modis_IWP_vs_ReffICE)) & + cospOUT%modis_IWP_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffICE)) & cospOUT%modis_Optical_Thickness_vs_ReffICE(:,:,:) = R_UNDEF if (associated(cospOUT%modis_Optical_Thickness_vs_ReffLIQ)) & @@ -3331,7 +3583,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, endif endif if (any([Lcloudsat_subcolumn,Lcloudsat_column,Lradar_lidar_tcc,Llidar_only_freq_cloud, & - Lcloudsat_tcc, Lcloudsat_tcc2])) then + Lcloudsat_tcc, Lcloudsat_tcc2, Lcloudsat_modis_wr])) then if (any(cospIN%z_vol_cloudsat .lt. 0)) then nError=nError+1 errorMessage(nError) = 'ERROR: COSP input variable: cospIN%z_vol_cloudsat contains values out of range' @@ -3341,12 +3593,15 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. Lcloudsat_tcc = .false. Lcloudsat_tcc2 = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%cloudsat_cfad_ze)) cospOUT%cloudsat_cfad_ze(:,:,:) = R_UNDEF if (associated(cospOUT%cloudsat_Ze_tot)) cospOUT%cloudsat_Ze_tot(:,:,:) = R_UNDEF if (associated(cospOUT%lidar_only_freq_cloud)) cospOUT%lidar_only_freq_cloud(:,:) = R_UNDEF if (associated(cospOUT%radar_lidar_tcc)) cospOUT%radar_lidar_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc)) cospOUT%cloudsat_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc2)) cospOUT%cloudsat_tcc2(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif if (any(cospIN%kr_vol_cloudsat .lt. 0)) then nError=nError+1 @@ -3357,12 +3612,15 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. Lcloudsat_tcc = .false. Lcloudsat_tcc2 = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%cloudsat_cfad_ze)) cospOUT%cloudsat_cfad_ze(:,:,:) = R_UNDEF if (associated(cospOUT%cloudsat_Ze_tot)) cospOUT%cloudsat_Ze_tot(:,:,:) = R_UNDEF if (associated(cospOUT%lidar_only_freq_cloud)) cospOUT%lidar_only_freq_cloud(:,:) = R_UNDEF if (associated(cospOUT%radar_lidar_tcc)) cospOUT%radar_lidar_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc)) cospOUT%cloudsat_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc2)) cospOUT%cloudsat_tcc2(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif if (any(cospIN%g_vol_cloudsat .lt. 0)) then nError=nError+1 @@ -3373,12 +3631,15 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, Llidar_only_freq_cloud = .false. Lcloudsat_tcc = .false. Lcloudsat_tcc2 = .false. + Lcloudsat_modis_wr = .false. if (associated(cospOUT%cloudsat_cfad_ze)) cospOUT%cloudsat_cfad_ze(:,:,:) = R_UNDEF if (associated(cospOUT%cloudsat_Ze_tot)) cospOUT%cloudsat_Ze_tot(:,:,:) = R_UNDEF if (associated(cospOUT%lidar_only_freq_cloud)) cospOUT%lidar_only_freq_cloud(:,:) = R_UNDEF if (associated(cospOUT%radar_lidar_tcc)) cospOUT%radar_lidar_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc)) cospOUT%cloudsat_tcc(:) = R_UNDEF if (associated(cospOUT%cloudsat_tcc2)) cospOUT%cloudsat_tcc2(:) = R_UNDEF + if (associated(cospOUT%cfodd_ntotal)) cospOUT%cfodd_ntotal(:,:,:,:) = R_UNDEF + if (associated(cospOUT%wr_occfreq_ntotal)) cospOUT%wr_occfreq_ntotal(:,:) = R_UNDEF endif endif !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -3648,7 +3909,7 @@ subroutine cosp_errorCheck(cospgridIN, cospIN, Lisccp_subcolumn, Lisccp_column, if (size(cospgridIN%pfull,2) .ne. cospIN%Nlevels .OR. & size(cospgridIN%at,2) .ne. cospIN%Nlevels .OR. & size(cospgridIN%qv,2) .ne. cospIN%Nlevels .OR. & - size(cospgridIN%hgt_matrix_half,2) .ne. cospIN%Nlevels+1 .OR. & + size(cospgridIN%hgt_matrix_half,2) .ne. cospIN%Nlevels .OR. & size(cospgridIN%phalf,2) .ne. cospIN%Nlevels+1 .OR. & size(cospgridIN%qv,2) .ne. cospIN%Nlevels) then Lrttov_column = .false. diff --git a/components/eam/src/physics/cosp2/local/cosp_config.F90 b/components/eam/src/physics/cosp2/local/cosp_config.F90 new file mode 100644 index 00000000000..c1a4d573d0f --- /dev/null +++ b/components/eam/src/physics/cosp2/local/cosp_config.F90 @@ -0,0 +1,502 @@ +! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +! Copyright (c) 2015, Regents of the University of Colorado +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without modification, are +! permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this list of +! conditions and the following disclaimer. +! +! 2. 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. +! +! 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDERS 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 +! THE COPYRIGHT HOLDER 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. +! +! History: +! Jul 2007 - A. Bodas-Salcedo - Initial version +! Jul 2008 - A. Bodas-Salcedo - Added definitions of ISCCP axes +! Oct 2008 - H. Chepfer - Added PARASOL_NREFL +! Jun 2010 - R. Marchand - Modified to support quickbeam V3, added ifdef for +! hydrometeor definitions +! May 2015 - D. Swales - Tidied up. Set up appropriate fields during initialization. +! June 2015- D. Swales - Moved hydrometeor class variables to hydro_class_init in +! the module quickbeam_optics. +! Mar 2016 - D. Swales - Added scops_ccfrac. Was previously hardcoded in prec_scops.f90. +! Mar 2018 - R. Guzman - Added LIDAR_NTYPE for the OPAQ diagnostics +! Apr 2018 - R. Guzman - Added parameters for GROUND LIDAR and ATLID simulators +! Nov 2018 - T. Michibata - Added CloudSat+MODIS Warmrain Diagnostics +! Mar 2024 - C. Wall - Added MODIS joint-histogram diagnostics +! +! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +MODULE MOD_COSP_CONFIG + USE COSP_KINDS, ONLY: wp,dp + IMPLICIT NONE + + ! ##################################################################################### + ! Common COSP information + ! ##################################################################################### + character(len=32) :: & + COSP_VERSION ! COSP Version ID (set in cosp_interface_init) + real(wp),parameter :: & + R_UNDEF = -1.0E30, & ! Missing value + R_GROUND = -1.0E20, & ! Flag for below ground results + scops_ccfrac = 0.05 ! Fraction of column (or subcolumn) covered with convective + ! precipitation (default is 5%). *NOTE* This quantity may vary + ! between modeling centers. + logical :: & + use_vgrid ! True=Use new grid for L3 CLOUDAT and CALIPSO + integer,parameter :: & + SR_BINS = 15, & ! Number of bins (backscattering coefficient) in CALOPSO LIDAR simulator. + N_HYDRO = 9 ! Number of hydrometeor classes used by quickbeam radar simulator. + + ! #################################################################################### + ! Joint histogram bin-boundaries + ! tau is used by ISCCP and MISR + ! pres is used by ISCCP + ! hgt is used by MISR + ! ReffLiq is used by MODIS + ! ReffIce is used by MODIS + ! *NOTE* ALL JOINT-HISTOGRAM BIN BOUNDARIES ARE DECLARED AND DEFINED HERE IN + ! COSP_CONFIG, WITH THE EXCEPTION OF THE TAU AXIS USED BY THE MODIS SIMULATOR, + ! WHICH IS SET DURING INITIALIZATION IN COSP_INTERFACE_INIT. + ! #################################################################################### + ! Optical depth bin axis + integer,parameter :: & + ntau=7 + real(wp),parameter,dimension(ntau+1) :: & + tau_binBounds = (/0.0, 0.3, 1.3, 3.6, 9.4, 23., 60., 10000./) + real(wp),parameter,dimension(ntau) :: & + tau_binCenters = (/0.15, 0.80, 2.45, 6.5, 16.2, 41.5, 100.0/) + real(wp),parameter,dimension(2,ntau) :: & + tau_binEdges = reshape(source=(/0.0, 0.3, 0.3, 1.3, 1.3, 3.6, 3.6, & + 9.4, 9.4, 23.0, 23.0, 60.0, 60.0, 100000.0/), & + shape=(/2,ntau/)) + + ! Optical depth bin axes (ONLY USED BY MODIS SIMULATOR IN v1.4) + integer :: l,k + integer,parameter :: & + ntauV1p4 = 6 + real(wp),parameter,dimension(ntauV1p4+1) :: & + tau_binBoundsV1p4 = (/0.3, 1.3, 3.6, 9.4, 23., 60., 10000./) + real(wp),parameter,dimension(2,ntauV1p4) :: & + tau_binEdgesV1p4 = reshape(source =(/tau_binBoundsV1p4(1),((tau_binBoundsV1p4(k),l=1,2), & + k=2,ntauV1p4),100000._wp/),shape = (/2,ntauV1p4/)) + real(wp),parameter,dimension(ntauV1p4) :: & + tau_binCentersV1p4 = (tau_binEdgesV1p4(1,:)+tau_binEdgesV1p4(2,:))/2._wp + + ! Cloud-top height pressure bin axis + integer,parameter :: & + npres = 7 + real(wp),parameter,dimension(npres+1) :: & + pres_binBounds = (/0., 180., 310., 440., 560., 680., 800., 10000./) + real(wp),parameter,dimension(npres) :: & + pres_binCenters = (/90000., 74000., 62000., 50000., 37500., 24500., 9000./) + real(wp),parameter,dimension(2,npres) :: & + pres_binEdges = reshape(source=(/100000.0, 80000.0, 80000.0, 68000.0, 68000.0, & + 56000.0, 56000.0, 44000.0, 44000.0, 31000.0, & + 31000.0, 18000.0, 18000.0, 0.0/), & + shape=(/2,npres/)) + + ! Cloud-top height bin axis #1 + integer,parameter :: & + nhgt = 16 + real(wp),parameter,dimension(nhgt+1) :: & + hgt_binBounds = (/-.99,0.,0.5,1.,1.5,2.,2.5,3.,4.,5.,7.,9.,11.,13.,15.,17.,99./) + real(wp),parameter,dimension(nhgt) :: & + hgt_binCenters = 1000*(/0.,0.25,0.75,1.25,1.75,2.25,2.75,3.5,4.5,6.,8.,10.,12., & + 14.5,16.,18./) + real(wp),parameter,dimension(2,nhgt) :: & + hgt_binEdges = 1000.0*reshape(source=(/-99.0, 0.0, 0.0, 0.5, 0.5, 1.0, 1.0, 1.5, & + 1.5, 2.0, 2.0, 2.5, 2.5, 3.0, 3.0, 4.0, & + 4.0, 5.0, 5.0, 7.0, 7.0, 9.0, 9.0,11.0, & + 11.0,13.0,13.0,15.0,15.0,17.0,17.0,99.0/),& + shape=(/2,nhgt/)) + + ! Liquid and Ice particle bins for MODIS joint histogram of optical-depth and particle + ! size + ! Bin edges match Pincus et al. 2023 observational data (doi:10.5194/essd-15-2483-2023) + integer :: i,j + integer,parameter :: & + nReffLiq = 6, & ! Number of ReffLiq bins for tau/ReffLiq and LWP/ReffLiq joint-histogram + nReffIce = 6 ! Number of ReffIce bins for tau/ReffICE and IWP/ReffIce joint-histogram + real(wp),parameter,dimension(nReffLiq+1) :: & + reffLIQ_binBounds = (/4.0e-6, 8e-6, 1.0e-5, 1.25e-5, 1.5e-5, 2.0e-5, 3.0e-5/) + real(wp),parameter,dimension(nReffIce+1) :: & + reffICE_binBounds = (/5.0e-6, 1.0e-5, 2.0e-5, 3.0e-5, 4.0e-5, 5.0e-5, 6.0e-5/) + real(wp),parameter,dimension(2,nReffICE) :: & + reffICE_binEdges = reshape(source=(/reffICE_binBounds(1),((reffICE_binBounds(k), & + l=1,2),k=2,nReffICE),reffICE_binBounds(nReffICE+1)/), & + shape = (/2,nReffICE/)) + real(wp),parameter,dimension(2,nReffLIQ) :: & + reffLIQ_binEdges = reshape(source=(/reffLIQ_binBounds(1),((reffLIQ_binBounds(k), & + l=1,2),k=2,nReffLIQ),reffLIQ_binBounds(nReffLIQ+1)/), & + shape = (/2,nReffLIQ/)) + real(wp),parameter,dimension(nReffICE) :: & + reffICE_binCenters = (reffICE_binEdges(1,:)+reffICE_binEdges(2,:))/2._wp + real(wp),parameter,dimension(nReffLIQ) :: & + reffLIQ_binCenters = (reffLIQ_binEdges(1,:)+reffLIQ_binEdges(2,:))/2._wp + + ! LWP and IWP bins for MODIS joint histogram of (1) LWP and droplet size + ! and (2) IWP and particle size + integer, parameter :: & + nLWP = 7, & ! Number of bins for LWP/ReffLiq joint-histogram + nIWP = 7 ! Number of bins for IWP/ReffIce joint-histogram + real(wp),parameter,dimension(nLWP+1) :: & + LWP_binBounds = (/0., 0.01, 0.03, 0.06, 0.10, 0.15, 0.25, 20.0/) ! kg/m2 + real(wp),parameter,dimension(nIWP+1) :: & + IWP_binBounds = (/0., 0.02, 0.05, 0.10, 0.20, 0.40, 1.00, 20.0/) ! kg/m2 + real(wp),parameter,dimension(2,nLWP) :: & + LWP_binEdges = reshape(source=(/LWP_binBounds(1),((LWP_binBounds(k), & + l=1,2),k=2,nLWP),LWP_binBounds(nLWP+1)/), & + shape = (/2,nLWP/)) + real(wp),parameter,dimension(2,nIWP) :: & + IWP_binEdges = reshape(source=(/IWP_binBounds(1),((IWP_binBounds(k), & + l=1,2),k=2,nIWP),IWP_binBounds(nIWP+1)/), & + shape = (/2,nIWP/)) + real(wp),parameter,dimension(nLWP) :: & + LWP_binCenters = (LWP_binEdges(1,:)+LWP_binEdges(2,:))/2._wp + real(wp),parameter,dimension(nIWP) :: & + IWP_binCenters = (IWP_binEdges(1,:)+IWP_binEdges(2,:))/2._wp + ! #################################################################################### + ! Constants used by RTTOV. + ! #################################################################################### + integer,parameter :: & + RTTOV_MAX_CHANNELS = 20 + character(len=256),parameter :: & + rttovDir = '/homedata/rguzman/CALIPSO/RTTOV/rttov_11.3/' + ! #################################################################################### + ! Constants used by the PARASOL simulator. + ! #################################################################################### + integer,parameter :: & + PARASOL_NREFL = 5, & ! Number of angles in LUT + PARASOL_NTAU = 7 ! Number of optical depths in LUT + real(wp),parameter,dimension(PARASOL_NREFL) :: & + PARASOL_SZA = (/0.0, 20.0, 40.0, 60.0, 80.0/) + REAL(WP),parameter,dimension(PARASOL_NTAU) :: & + PARASOL_TAU = (/0., 1., 5., 10., 20., 50., 100./) + + ! LUTs + REAL(WP),parameter,dimension(PARASOL_NREFL,PARASOL_NTAU) :: & + ! LUT for liquid particles + rlumA = reshape(source=(/ 0.03, 0.03, 0.03, 0.03, 0.03, & + 0.090886, 0.072185, 0.058410, 0.052498, 0.034730, & + 0.283965, 0.252596, 0.224707, 0.175844, 0.064488, & + 0.480587, 0.436401, 0.367451, 0.252916, 0.081667, & + 0.695235, 0.631352, 0.509180, 0.326551, 0.098215, & + 0.908229, 0.823924, 0.648152, 0.398581, 0.114411, & + 1.0, 0.909013, 0.709554, 0.430405, 0.121567/), & + shape=(/PARASOL_NREFL,PARASOL_NTAU/)), & + ! LUT for ice particles + rlumB = reshape(source=(/ 0.03, 0.03, 0.03, 0.03, 0.03, & + 0.092170, 0.087082, 0.083325, 0.084935, 0.054157, & + 0.311941, 0.304293, 0.285193, 0.233450, 0.089911, & + 0.511298, 0.490879, 0.430266, 0.312280, 0.107854, & + 0.712079, 0.673565, 0.563747, 0.382376, 0.124127, & + 0.898243, 0.842026, 0.685773, 0.446371, 0.139004, & + 0.976646, 0.912966, 0.737154, 0.473317, 0.145269/), & + shape=(/PARASOL_NREFL,PARASOL_NTAU/)) + + ! #################################################################################### + ! ISCCP simulator tau/CTP joint histogram information + ! #################################################################################### + integer,parameter :: & + numISCCPTauBins = ntau, & ! Number of optical depth bins + numISCCPPresBins = npres ! Number of pressure bins + real(wp),parameter,dimension(ntau+1) :: & + isccp_histTau = tau_binBounds ! Joint-histogram boundaries (optical depth) + real(wp),parameter,dimension(npres+1) :: & + isccp_histPres = pres_binBounds ! Joint-histogram boundaries (cloud pressure) + real(wp),parameter,dimension(ntau) :: & + isccp_histTauCenters = tau_binCenters ! Joint histogram bin centers (optical depth) + real(wp),parameter,dimension(npres) :: & + isccp_histPresCenters = pres_binCenters ! Joint histogram bin centers (cloud pressure) + real(wp),parameter,dimension(2,ntau) :: & + isccp_histTauEdges = tau_binEdges ! Joint histogram bin edges (optical depth) + real(wp),parameter,dimension(2,npres) :: & + isccp_histPresEdges = pres_binEdges ! Joint histogram bin edges (cloud pressure) + + ! #################################################################################### + ! MISR simulator tau/CTH joint histogram information + ! #################################################################################### + integer,parameter :: & + numMISRHgtBins = nhgt, & ! Number of cloud-top height bins + numMISRTauBins = ntau ! Number of optical depth bins + ! Joint histogram boundaries + real(wp),parameter,dimension(numMISRHgtBins+1) :: & + misr_histHgt = hgt_binBounds ! Joint-histogram boundaries (cloud height) + real(wp),parameter,dimension(numMISRTauBins+1) :: & + misr_histTau = tau_binBounds ! Joint-histogram boundaries (optical-depth) + real(wp),parameter,dimension(numMISRHgtBins) :: & + misr_histHgtCenters = hgt_binCenters ! Joint-histogram bin centers (cloud height) + real(wp),parameter,dimension(2,numMISRHgtBins) :: & + misr_histHgtEdges = hgt_BinEdges ! Joint-histogram bin edges (cloud height) + + ! #################################################################################### + ! MODIS simulator tau/CTP joint histogram information + ! #################################################################################### + integer,parameter :: & + numMODISPresBins = npres ! Number of pressure bins for joint-histogram + real(wp),parameter,dimension(numMODISPresBins + 1) :: & + modis_histPres = 100*pres_binBounds ! Joint-histogram boundaries (cloud pressure) + real(wp),parameter,dimension(2, numMODISPresBins) :: & + modis_histPresEdges = 100*pres_binEdges ! Joint-histogram bin edges (cloud pressure) + real(wp),parameter,dimension(numMODISPresBins) :: & + modis_histPresCenters = 100*pres_binCenters ! Joint-histogram bin centers (cloud pressure) + + ! For the MODIS simulator we want to preserve the ability for cospV1.4.0 to use the + ! old histogram bin boundaries for optical depth, so these are set up in initialization. + integer :: & + numMODISTauBins ! Number of tau bins for joint-histogram + real(wp),allocatable,dimension(:) :: & + modis_histTau ! Joint-histogram boundaries (optical depth) + real(wp),allocatable,dimension(:,:) :: & + modis_histTauEdges ! Joint-histogram bin edges (optical depth) + real(wp),allocatable,dimension(:) :: & + modis_histTauCenters ! Joint-histogram bin centers (optical depth) + + ! #################################################################################### + ! MODIS simulator tau/ReffICE and tau/ReffLIQ joint-histogram information + ! #################################################################################### + ! Ice + integer,parameter :: & + numMODISReffIceBins = nReffIce ! Number of bins for joint-histogram + real(wp),parameter,dimension(nReffIce+1) :: & + modis_histReffIce = reffICE_binBounds ! Effective radius bin boundaries + real(wp),parameter,dimension(nReffIce) :: & + modis_histReffIceCenters = reffICE_binCenters ! Effective radius bin centers + real(wp),parameter,dimension(2,nReffICE) :: & + modis_histReffIceEdges = reffICE_binEdges ! Effective radius bin edges + + ! Liquid + integer,parameter :: & + numMODISReffLiqBins = nReffLiq ! Number of bins for joint-histogram + real(wp),parameter,dimension(nReffLiq+1) :: & + modis_histReffLiq = reffLIQ_binBounds ! Effective radius bin boundaries + real(wp),parameter,dimension(nReffLiq) :: & + modis_histReffLiqCenters = reffLIQ_binCenters ! Effective radius bin centers + real(wp),parameter,dimension(2,nReffLiq) :: & + modis_histReffLiqEdges = reffLIQ_binEdges ! Effective radius bin edges + ! #################################################################################### + ! MODIS simulator LWP/ReffLIQ and IWP/ReffIce joint-histogram information + ! #################################################################################### + ! Liquid + integer,parameter :: & + numMODISLWPBins = nLWP ! Number of bins for joint-histogram + real(wp),parameter,dimension(nLWP+1) :: & + modis_histLWP = LWP_binBounds ! LWP bin boundaries + real(wp),parameter,dimension(nLWP) :: & + modis_histLWPCenters = LWP_binCenters ! LWP bin centers + real(wp),parameter,dimension(2,nLWP) :: & + modis_histLWPEdges = LWP_binEdges ! LWP bin edges + + ! Ice + integer,parameter :: & + numMODISIWPBins = nIWP ! Number of bins for joint-histogram + real(wp),parameter,dimension(nIWP+1) :: & + modis_histIWP = IWP_binBounds ! IWP bin boundaries + real(wp),parameter,dimension(nIWP) :: & + modis_histIWPCenters = IWP_binCenters ! IWP bin centers + real(wp),parameter,dimension(2,nIWP) :: & + modis_histIWPEdges = IWP_binEdges ! IWP bin edges + + ! #################################################################################### + ! CLOUDSAT reflectivity histogram information + ! #################################################################################### + integer,parameter :: & + CLOUDSAT_DBZE_BINS = 15, & ! Number of dBZe bins in histogram (cfad) + CLOUDSAT_DBZE_MIN = -100, & ! Minimum value for radar reflectivity + CLOUDSAT_DBZE_MAX = 80, & ! Maximum value for radar reflectivity + CLOUDSAT_CFAD_ZE_MIN = -50, & ! Lower value of the first CFAD Ze bin + CLOUDSAT_CFAD_ZE_WIDTH = 5 ! Bin width (dBZe) + + real(wp),parameter,dimension(CLOUDSAT_DBZE_BINS+1) :: & + cloudsat_histRef = (/CLOUDSAT_DBZE_MIN,(/(i, i=int(CLOUDSAT_CFAD_ZE_MIN+CLOUDSAT_CFAD_ZE_WIDTH),& + int(CLOUDSAT_CFAD_ZE_MIN+(CLOUDSAT_DBZE_BINS-1)*CLOUDSAT_CFAD_ZE_WIDTH), & + int(CLOUDSAT_CFAD_ZE_WIDTH))/),CLOUDSAT_DBZE_MAX/) + real(wp),parameter,dimension(2,CLOUDSAT_DBZE_BINS) :: & + cloudsat_binEdges = reshape(source=(/cloudsat_histRef(1),((cloudsat_histRef(k), & + l=1,2),k=2,CLOUDSAT_DBZE_BINS),cloudsat_histRef(CLOUDSAT_DBZE_BINS+1)/),& + shape = (/2,CLOUDSAT_DBZE_BINS/)) + real(wp),parameter,dimension(CLOUDSAT_DBZE_BINS) :: & + cloudsat_binCenters = (cloudsat_binEdges(1,:)+cloudsat_binEdges(2,:))/2._wp + + ! Parameters for Cloudsat near-surface precipitation diagnostics. + ! Precipitation classes. + integer, parameter :: & + nCloudsatPrecipClass = 10 + integer, parameter :: & + pClass_noPrecip = 0, & ! No precipitation + pClass_Rain1 = 1, & ! Rain possible + pClass_Rain2 = 2, & ! Rain probable + pClass_Rain3 = 3, & ! Rain certain + pClass_Snow1 = 4, & ! Snow possible + pClass_Snow2 = 5, & ! Snow certain + pClass_Mixed1 = 6, & ! Mixed-precipitation possible + pClass_Mixed2 = 7, & ! Mixed-precipitation certain + pClass_Rain4 = 8, & ! Heavy rain + pClass_default = 9 ! Default + ! Reflectivity bin boundaries, used by decision tree to classify precipitation type. + real(wp), dimension(4),parameter :: & + Zenonbinval =(/0._wp, -5._wp, -7.5_wp, -15._wp/) + real(wp), dimension(6),parameter :: & + Zbinvallnd = (/10._wp, 5._wp, 2.5_wp, -2.5_wp, -5._wp, -15._wp/) + ! Vertical level index(Nlvgrid) for Cloudsat precipitation occurence/frequency diagnostics. + ! Level 39 of Nlvgrid(40) is 480-960m. + integer, parameter :: & + cloudsat_preclvl = 39 + + ! #################################################################################### + ! CLOUDSAT and MODIS joint product information (2018.11.22) + ! #################################################################################### + ! @ COSP_DIAG_WARMRAIN: + integer, parameter :: CFODD_NCLASS = 3 ! # of classes for CFODD (classified by MODIS Reff) + integer, parameter :: WR_NREGIME = 3 ! # of warm-rain regimes (non-precip/drizzling/raining) + integer, parameter :: SGCLD_CLR = 0 ! sub-grid cloud ID (fracout): clear-sky + integer, parameter :: SGCLD_ST = 1 ! sub-grid cloud ID (fracout): stratiform + integer, parameter :: SGCLD_CUM = 2 ! sub-grid cloud ID (fracout): cumulus + real(wp),parameter :: CWP_THRESHOLD = 0.00 ! cloud water path threshold + real(wp),parameter :: COT_THRESHOLD = 0.30 ! cloud optical thickness threshold + real(wp),parameter,dimension(CFODD_NCLASS+1) :: & + CFODD_BNDRE = (/5.0e-6, 12.0e-6, 18.0e-6, 35.0e-6/) ! Reff bnds + real(wp),parameter,dimension(2) :: & + CFODD_BNDZE = (/-15.0, 0.0/) ! dBZe bnds (cloud/drizzle/precip) + real(wp),parameter :: CFODD_DBZE_MIN = -30.0 ! Minimum value of CFODD dBZe bin + real(wp),parameter :: CFODD_DBZE_MAX = 20.0 ! Maximum value of CFODD dBZe bin + real(wp),parameter :: CFODD_ICOD_MIN = 0.0 ! Minimum value of CFODD ICOD bin + real(wp),parameter :: CFODD_ICOD_MAX = 60.0 ! Maximum value of CFODD ICOD bin + real(wp),parameter :: CFODD_DBZE_WIDTH = 2.0 ! Bin width (dBZe) + real(wp),parameter :: CFODD_ICOD_WIDTH = 2.0 ! Bin width (ICOD) + integer,parameter :: & + CFODD_NDBZE = INT( (CFODD_DBZE_MAX-CFODD_DBZE_MIN)/CFODD_DBZE_WIDTH ) ! Number of CFODD dBZe bins + integer,parameter :: & + CFODD_NICOD = INT( (CFODD_ICOD_MAX-CFODD_ICOD_MIN)/CFODD_ICOD_WIDTH ) ! Number of CFODD ICOD bins + real(wp),parameter,dimension(CFODD_NDBZE+1) :: & + CFODD_HISTDBZE = (/int(CFODD_DBZE_MIN),(/(i, i=int(CFODD_DBZE_MIN+CFODD_DBZE_WIDTH), & + int(CFODD_DBZE_MIN+(CFODD_NDBZE-1)*CFODD_DBZE_WIDTH), & + int(CFODD_DBZE_WIDTH))/),int(CFODD_DBZE_MAX)/) + real(wp),parameter,dimension(CFODD_NICOD+1) :: & + CFODD_HISTICOD = (/int(CFODD_ICOD_MIN),(/(i, i=int(CFODD_ICOD_MIN+CFODD_ICOD_WIDTH), & + int(CFODD_ICOD_MIN+(CFODD_NICOD-1)*CFODD_ICOD_WIDTH), & + int(CFODD_ICOD_WIDTH))/),int(CFODD_ICOD_MAX)/) + real(wp),parameter,dimension(2,CFODD_NDBZE) :: & + CFODD_HISTDBZEedges = reshape(source=(/CFODD_HISTDBZE(1),((CFODD_HISTDBZE(k), & + l=1,2),k=2,CFODD_NDBZE),CFODD_HISTDBZE(CFODD_NDBZE+1)/), & + shape = (/2,CFODD_NDBZE/)) + real(wp),parameter,dimension(CFODD_NDBZE) :: & + CFODD_HISTDBZEcenters = (CFODD_HISTDBZEedges(1,:)+CFODD_HISTDBZEedges(2,:))/2._wp + real(wp),parameter,dimension(2,CFODD_NICOD) :: & + CFODD_HISTICODedges = reshape(source=(/CFODD_HISTICOD(1),((CFODD_HISTICOD(k), & + l=1,2),k=2,CFODD_NICOD),CFODD_HISTICOD(CFODD_NICOD+1)/), & + shape = (/2,CFODD_NICOD/)) + real(wp),parameter,dimension(CFODD_NICOD) :: & + CFODD_HISTICODcenters = (CFODD_HISTICODedges(1,:)+CFODD_HISTICODedges(2,:))/2._wp + + ! #################################################################################### + ! Parameters used by the CALIPSO LIDAR simulator + ! #################################################################################### + ! CALISPO backscatter histogram bins + real(wp),parameter :: & + S_cld = 5.0, & ! Threshold for cloud detection + S_att = 0.01, & ! + S_cld_att = 30. ! Threshold for undefined cloud phase detection + real(wp),parameter,dimension(SR_BINS+1) :: & + calipso_histBsct = (/-1.,0.01,1.2,3.0,5.0,7.0,10.0,15.0,20.0,25.0,30.0,40.0,50.0, & + 60.0,80.0,999./) ! Backscatter histogram bins + real(wp),parameter,dimension(2,SR_BINS) :: & + calipso_binEdges = reshape(source=(/calipso_histBsct(1),((calipso_histBsct(k), & + l=1,2),k=2,SR_BINS),calipso_histBsct(SR_BINS+1)/), & + shape = (/2,SR_BINS/)) + real(wp),parameter,dimension(SR_BINS) :: & + calipso_binCenters = (calipso_binEdges(1,:)+calipso_binEdges(2,:))/2._wp + + integer,parameter :: & + LIDAR_NTEMP = 40, & + LIDAR_NCAT = 4, & ! Number of categories for cloudtop heights (high/mid/low/tot) + LIDAR_NTYPE = 3 ! Number of categories for OPAQ (opaque/thin cloud + z_opaque) + real(wp),parameter,dimension(LIDAR_NTEMP) :: & + LIDAR_PHASE_TEMP= & + (/-91.5,-88.5,-85.5,-82.5,-79.5,-76.5,-73.5,-70.5,-67.5,-64.5, & + -61.5,-58.5,-55.5,-52.5,-49.5,-46.5,-43.5,-40.5,-37.5,-34.5, & + -31.5,-28.5,-25.5,-22.5,-19.5,-16.5,-13.5,-10.5, -7.5, -4.5, & + -1.5, 1.5, 4.5, 7.5, 10.5, 13.5, 16.5, 19.5, 22.5, 25.5/) + real(wp),parameter,dimension(2,LIDAR_NTEMP) :: & + LIDAR_PHASE_TEMP_BNDS=reshape(source= & + (/-273.15, -90., -90., -87., -87., -84., -84., -81., -81., -78., & + -78., -75., -75., -72., -72., -69., -69., -66., -66., -63., & + -63., -60., -60., -57., -57., -54., -54., -51., -51., -48., & + -48., -45., -45., -42., -42., -39., -39., -36., -36., -33., & + -33., -30., -30., -27., -27., -24., -24., -21., -21., -18., & + -18., -15., -15., -12., -12., -9., -9., -6., -6., -3., & + -3., 0., 0., 3., 3., 6., 6., 9., 9., 12., & + 12., 15., 15., 18., 18., 21., 21., 24., 24., 100. /), & + shape=(/2,40/)) + + ! #################################################################################### + ! Parameters used by the GROUND LIDAR simulator + ! #################################################################################### + ! GROUND LIDAR backscatter histogram bins +! real(wp),parameter :: & +! S_cld = 5.0, & ! Threshold for cloud detection +! S_att = 0.01, & ! +! S_cld_att = 30. ! Threshold for undefined cloud phase detection + real(wp),parameter,dimension(SR_BINS+1) :: & + grLidar532_histBsct = (/-1.,0.01,1.2,3.0,5.0,7.0,10.0,15.0,20.0,25.0,30.0,40.0,50.0, & + 60.0,80.0,999./) ! Backscatter histogram bins + real(wp),parameter,dimension(2,SR_BINS) :: & + grLidar532_binEdges = reshape(source=(/grLidar532_histBsct(1),((grLidar532_histBsct(k), & + l=1,2),k=2,SR_BINS),grLidar532_histBsct(SR_BINS+1)/), & + shape = (/2,SR_BINS/)) + real(wp),parameter,dimension(SR_BINS) :: & + grLidar532_binCenters = (grLidar532_binEdges(1,:)+grLidar532_binEdges(2,:))/2._wp + +! integer,parameter :: & +! LIDAR_NCAT = 4 ! Number of categories for cloudtop heights (high/mid/low/tot) + + ! #################################################################################### + ! Parameters used by the ATLID LIDAR simulator + ! #################################################################################### + ! ATLID LIDAR backscatter histogram bins + real(wp),parameter :: & + S_cld_atlid = 1.74, & ! Threshold for cloud detection + S_att_atlid = 0.01, & ! + S_cld_att_atlid = 6.67 ! Threshold for undefined cloud phase detection + real(wp),parameter,dimension(SR_BINS+1) :: & + atlid_histBsct = (/-1.,0.01,1.03,1.38,1.74,2.07,2.62,3.65,4.63,5.63,6.67,8.8,11.25, & + 13.2,17.2,999./) ! Backscatter histogram bins + real(wp),parameter,dimension(2,SR_BINS) :: & + atlid_binEdges = reshape(source=(/atlid_histBsct(1),((atlid_histBsct(k), & + l=1,2),k=2,SR_BINS),atlid_histBsct(SR_BINS+1)/), & + shape = (/2,SR_BINS/)) + real(wp),parameter,dimension(SR_BINS) :: & + atlid_binCenters = (atlid_binEdges(1,:)+atlid_binEdges(2,:))/2._wp + +! integer,parameter :: & +! LIDAR_NCAT = 4 ! Number of categories for cloudtop heights (high/mid/low/tot) + + ! #################################################################################### + ! New vertical grid used by CALIPSO and CLOUDSAT L3 (set up during initialization) + ! #################################################################################### + integer :: & + Nlvgrid ! Number of levels in New grid + real(wp),dimension(:),allocatable :: & + vgrid_zl, & ! New grid bottoms + vgrid_zu, & ! New grid tops + vgrid_z, & ! New grid center + dz ! dZ + +END MODULE MOD_COSP_CONFIG diff --git a/components/eam/src/physics/cosp2/local/modis_simulator.F90 b/components/eam/src/physics/cosp2/local/modis_simulator.F90 new file mode 100644 index 00000000000..974c0172432 --- /dev/null +++ b/components/eam/src/physics/cosp2/local/modis_simulator.F90 @@ -0,0 +1,959 @@ +! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +! Copyright (c) 2015, Regents of the University of Colorado +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without modification, are +! permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this list of +! conditions and the following disclaimer. +! +! 2. 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. +! +! 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDERS 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 +! THE COPYRIGHT HOLDER 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. +! +! History +! May 2009: Robert Pincus - Initial version +! June 2009: Steve Platnick and Robert Pincus - Simple radiative transfer for size +! retrievals +! August 2009: Robert Pincus - Consistency and bug fixes suggested by Rick Hemler (GFDL) +! November 2009: Robert Pincus - Bux fixes and speed-ups after experience with Rick Hemler +! using AM2 (GFDL) +! January 2010: Robert Pincus - Added high, middle, low cloud fractions +! May 2015: Dustin Swales - Modified for COSPv2.0 +! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +! +! Notes on using the MODIS simulator: +! *) You may provide either layer-by-layer values of optical thickness at 0.67 and 2.1 +! microns, or optical thickness at 0.67 microns and ice- and liquid-water contents +! (in consistent units of your choosing) +! *) Required input also includes the optical thickness and cloud top pressure +! derived from the ISCCP simulator run with parameter top_height = 1. +! *) Cloud particle sizes are specified as radii, measured in meters, though within the +! module we use units of microns. Where particle sizes are outside the bounds used in +! the MODIS retrieval libraries (parameters re_water_min, re_ice_min, etc.) the +! simulator returns missing values (re_fill) +! +! When error conditions are encountered this code calls the function complain_and_die, +! supplied at the bottom of this module. Users probably want to replace this with +! something more graceful. +! +module mod_modis_sim + USE MOD_COSP_CONFIG, only: R_UNDEF,modis_histTau,modis_histPres,numMODISTauBins, & + numMODISPresBins,numMODISReffIceBins,numMODISReffLiqBins, & + modis_histReffIce,modis_histReffLiq, & + modis_histLWP,modis_histIWP, & + numMODISLWPBins,numMODISIWPBins + USE COSP_KINDS, ONLY: wp + use MOD_COSP_STATS, ONLY: hist2D + + implicit none + ! ########################################################################## + ! Retrieval parameters + integer, parameter :: & + num_trial_res = 15 ! Increase to make the linear pseudo-retrieval of size more accurate + + real(wp) :: & + min_OpticalThickness, & ! Minimum detectable optical thickness + CO2Slicing_PressureLimit, & ! Cloud with higher pressures use thermal methods, units Pa + CO2Slicing_TauLimit, & ! How deep into the cloud does CO2 slicing see? + phase_TauLimit, & ! How deep into the cloud does the phase detection see? + size_TauLimit, & ! Depth of the re retreivals + phaseDiscrimination_Threshold, & ! What fraction of total extincton needs to be in a single + ! category to make phase discrim. work? + re_fill, & ! + re_water_min, & ! Minimum effective radius (liquid) + re_water_max, & ! Maximum effective radius (liquid) + re_ice_min, & ! Minimum effective radius (ice) + re_ice_max, & ! Minimum effective radius (ice) + highCloudPressureLimit, & ! High cloud pressure limit (Pa) + lowCloudPressureLimit ! Low cloud pressure limit (Pa) + integer :: & + phaseIsNone, & ! + phaseIsLiquid, & ! + phaseIsIce, & ! + phaseIsUndetermined ! + + real(wp),dimension(num_trial_res) :: & + trial_re_w, & ! Near-IR optical params vs size for retrieval scheme (liquid) + trial_re_i ! Near-IR optical params vs size for retrieval scheme (ice) + real(wp),dimension(num_trial_res) :: & + g_w, & ! Assymettry parameter for size retrieval (liquid) + g_i, & ! Assymettry parameter for size retrieval (ice) + w0_w, & ! Single-scattering albedo for size retrieval (liquid) + w0_i ! Single-scattering albedo for size retrieval (ice) + ! Algorithmic parameters + real(wp),parameter :: & + ice_density = 0.93_wp ! Liquid density is 1. + +contains + ! ######################################################################################## + ! MODIS simulator using specified liquid and ice optical thickness in each layer + ! + ! Note: this simulator operates on all points; to match MODIS itself night-time + ! points should be excluded + ! + ! Note: the simulator requires as input the optical thickness and cloud top pressure + ! derived from the ISCCP simulator run with parameter top_height = 1. + ! If cloud top pressure is higher than about 700 mb, MODIS can't use CO2 slicing + ! and reverts to a thermal algorithm much like ISCCP's. Rather than replicate that + ! alogrithm in this simulator we simply report the values from the ISCCP simulator. + ! ######################################################################################## + subroutine modis_subcolumn(nSubCols, nLevels, pressureLevels, optical_thickness, & + tauLiquidFraction, g, w0,isccpCloudTopPressure, & + retrievedPhase, retrievedCloudTopPressure, & + retrievedTau, retrievedSize) + + ! INPUTS + integer,intent(in) :: & + nSubCols, & ! Number of subcolumns + nLevels ! Number of levels + real(wp),dimension(nLevels+1),intent(in) :: & + pressureLevels ! Gridmean pressure at layer edges (Pa) + real(wp),dimension(nSubCols,nLevels),intent(in) :: & + optical_thickness, & ! Subcolumn optical thickness @ 0.67 microns. + tauLiquidFraction, & ! Liquid water fraction + g, & ! Subcolumn assymetry parameter + w0 ! Subcolumn single-scattering albedo + real(wp),dimension(nSubCols),intent(in) :: & + isccpCloudTopPressure ! ISCCP retrieved cloud top pressure (Pa) + + ! OUTPUTS + integer, dimension(nSubCols), intent(inout) :: & + retrievedPhase ! MODIS retrieved phase (liquid/ice/other) + real(wp),dimension(nSubCols), intent(inout) :: & + retrievedCloudTopPressure, & ! MODIS retrieved CTP (Pa) + retrievedTau, & ! MODIS retrieved optical depth (unitless) + retrievedSize ! MODIS retrieved particle size (microns) + + ! LOCAL VARIABLES + logical, dimension(nSubCols) :: & + cloudMask + real(wp) :: & + integratedLiquidFraction, & + obs_Refl_nir + real(wp),dimension(num_trial_res) :: & + predicted_Refl_nir + integer :: & + i + + ! ######################################################################################## + ! Optical depth retrieval + ! This is simply a sum over the optical thickness in each layer. + ! It should agree with the ISCCP values after min values have been excluded. + ! ######################################################################################## + retrievedTau(1:nSubCols) = sum(optical_thickness(1:nSubCols,1:nLevels), dim = 2) + + ! ######################################################################################## + ! Cloud detection + ! does optical thickness exceed detection threshold? + ! ######################################################################################## + cloudMask = retrievedTau(1:nSubCols) >= min_OpticalThickness + + do i = 1, nSubCols + if(cloudMask(i)) then + ! ################################################################################## + ! Cloud top pressure determination + ! MODIS uses CO2 slicing for clouds with tops above about 700 mb and thermal + ! methods for clouds lower than that. For CO2 slicing we report the optical-depth + ! weighted pressure, integrating to a specified optical depth. + ! This assumes linear variation in p between levels. Linear in ln(p) is probably + ! better, though we'd need to deal with the lowest pressure gracefully. + ! ################################################################################## + retrievedCloudTopPressure(i) = cloud_top_pressure(nLevels,(/ 0._wp, optical_thickness(i,1:nLevels) /), & + pressureLevels(1:nLevels),CO2Slicing_TauLimit) + + ! ################################################################################## + ! Phase determination + ! Determine fraction of total tau that's liquid when ice and water contribute about + ! equally to the extinction we can't tell what the phase is. + ! ################################################################################## + integratedLiquidFraction = weight_by_extinction(nLevels,optical_thickness(i,1:nLevels), & + tauLiquidFraction(i, 1:nLevels), & + phase_TauLimit) + if(integratedLiquidFraction >= phaseDiscrimination_Threshold) then + retrievedPhase(i) = phaseIsLiquid + else if (integratedLiquidFraction <= 1._wp- phaseDiscrimination_Threshold) then + retrievedPhase(i) = phaseIsIce + else + retrievedPhase(i) = phaseIsUndetermined + end if + + ! ################################################################################## + ! Size determination + ! ################################################################################## + + ! Compute observed reflectance + obs_Refl_nir = compute_toa_reflectace(nLevels,optical_thickness(i,1:nLevels), g(i,1:nLevels), w0(i,1:nLevels)) + + ! Compute predicted reflectance + if(any(retrievedPhase(i) == (/ phaseIsLiquid, phaseIsUndetermined, phaseIsIce /))) then + if (retrievedPhase(i) == phaseIsLiquid .OR. retrievedPhase(i) == phaseIsUndetermined) then + predicted_Refl_nir(1:num_trial_res) = two_stream_reflectance(retrievedTau(i), & + g_w(1:num_trial_res), w0_w(1:num_trial_res)) + retrievedSize(i) = 1.0e-06_wp*interpolate_to_min(trial_re_w(1:num_trial_res), & + predicted_Refl_nir(1:num_trial_res), obs_Refl_nir) + else + predicted_Refl_nir(1:num_trial_res) = two_stream_reflectance(retrievedTau(i), & + g_i(1:num_trial_res), w0_i(1:num_trial_res)) + retrievedSize(i) = 1.0e-06_wp*interpolate_to_min(trial_re_i(1:num_trial_res), & + predicted_Refl_nir(1:num_trial_res), obs_Refl_nir) + endif + else + retrievedSize(i) = re_fill + endif + else + ! Values when we don't think there's a cloud. + retrievedCloudTopPressure(i) = R_UNDEF + retrievedPhase(i) = phaseIsNone + retrievedSize(i) = R_UNDEF + retrievedTau(i) = R_UNDEF + end if + end do + where((retrievedSize(1:nSubCols) < 0.).and.(retrievedSize(1:nSubCols) /= R_UNDEF)) & + retrievedSize(1:nSubCols) = 1.0e-06_wp*re_fill + + ! We use the ISCCP-derived CTP for low clouds, since the ISCCP simulator ICARUS + ! mimics what MODIS does to first order. + ! Of course, ISCCP cloud top pressures are in mb. + where(cloudMask(1:nSubCols) .and. retrievedCloudTopPressure(1:nSubCols) > CO2Slicing_PressureLimit) & + retrievedCloudTopPressure(1:nSubCols) = isccpCloudTopPressure! * 100._wp + + end subroutine modis_subcolumn + + ! ######################################################################################## + subroutine modis_column(nPoints,nSubCols,phase, cloud_top_pressure, optical_thickness, particle_size, & + Cloud_Fraction_Total_Mean, Cloud_Fraction_Water_Mean, Cloud_Fraction_Ice_Mean, & + Cloud_Fraction_High_Mean, Cloud_Fraction_Mid_Mean, Cloud_Fraction_Low_Mean, & + Optical_Thickness_Total_Mean, Optical_Thickness_Water_Mean, Optical_Thickness_Ice_Mean, & + Optical_Thickness_Total_MeanLog10, Optical_Thickness_Water_MeanLog10, Optical_Thickness_Ice_MeanLog10,& + Cloud_Particle_Size_Water_Mean, Cloud_Particle_Size_Ice_Mean, Cloud_Top_Pressure_Total_Mean, & + Liquid_Water_Path_Mean, Ice_Water_Path_Mean, & + Optical_Thickness_vs_Cloud_Top_Pressure,Optical_Thickness_vs_ReffIce,Optical_Thickness_vs_ReffLiq, & + Optical_Thickness_vs_Cloud_Top_Pressure_Liq, & + Optical_Thickness_vs_Cloud_Top_Pressure_Ice, & + LWP_vs_ReffLiq, IWP_vs_ReffIce & + ) + + ! INPUTS + integer,intent(in) :: & + nPoints, & ! Number of horizontal gridpoints + nSubCols ! Number of subcolumns + integer,intent(in), dimension(nPoints, nSubCols) :: & + phase + real(wp),intent(in),dimension(nPoints, nSubCols) :: & + cloud_top_pressure, & + optical_thickness, & + particle_size + + ! OUTPUTS + real(wp),intent(inout),dimension(nPoints) :: & ! + Cloud_Fraction_Total_Mean, & ! + Cloud_Fraction_Water_Mean, & ! + Cloud_Fraction_Ice_Mean, & ! + Cloud_Fraction_High_Mean, & ! + Cloud_Fraction_Mid_Mean, & ! + Cloud_Fraction_Low_Mean, & ! + Optical_Thickness_Total_Mean, & ! + Optical_Thickness_Water_Mean, & ! + Optical_Thickness_Ice_Mean, & ! + Optical_Thickness_Total_MeanLog10, & ! + Optical_Thickness_Water_MeanLog10, & ! + Optical_Thickness_Ice_MeanLog10, & ! + Cloud_Particle_Size_Water_Mean, & ! + Cloud_Particle_Size_Ice_Mean, & ! + Cloud_Top_Pressure_Total_Mean, & ! + Liquid_Water_Path_Mean, & ! + Ice_Water_Path_Mean ! + real(wp),intent(inout),dimension(nPoints,numMODISTauBins,numMODISPresBins) :: & + Optical_Thickness_vs_Cloud_Top_Pressure, & + Optical_Thickness_vs_Cloud_Top_Pressure_Liq, & + Optical_Thickness_vs_Cloud_Top_Pressure_Ice + real(wp),intent(inout),dimension(nPoints,numMODISLWPBins,numMODISReffLiqBins) :: & + LWP_vs_ReffLiq + real(wp),intent(inout),dimension(nPoints,numMODISIWPBins,numMODISReffIceBins) :: & + IWP_vs_ReffIce + real(wp),intent(inout),dimension(nPoints,numMODISTauBins,numMODISReffIceBins) :: & + Optical_Thickness_vs_ReffIce + real(wp),intent(inout),dimension(nPoints,numMODISTauBins,numMODISReffLiqBins) :: & + Optical_Thickness_vs_ReffLiq + + ! LOCAL VARIABLES + real(wp), parameter :: & + LWP_conversion = 2._wp/3._wp * 1000._wp ! MKS units + integer :: j + logical, dimension(nPoints,nSubCols) :: & + cloudMask, & + waterCloudMask, & + iceCloudMask, & + validRetrievalMask + real(wp),dimension(nPoints,nSubCols) :: & + tauWRK,ctpWRK,reffIceWRK,reffLiqWRK, & + tauLiqWRK,tauIceWRK,lwpWRK,iwpWRK + + ! ######################################################################################## + ! Include only those pixels with successful retrievals in the statistics + ! ######################################################################################## + validRetrievalMask(1:nPoints,1:nSubCols) = particle_size(1:nPoints,1:nSubCols) > 0. + cloudMask(1:nPoints,1:nSubCols) = phase(1:nPoints,1:nSubCols) /= phaseIsNone .and. & + validRetrievalMask(1:nPoints,1:nSubCols) + waterCloudMask(1:nPoints,1:nSubCols) = phase(1:nPoints,1:nSubCols) == phaseIsLiquid .and. & + validRetrievalMask(1:nPoints,1:nSubCols) + iceCloudMask(1:nPoints,1:nSubCols) = phase(1:nPoints,1:nSubCols) == phaseIsIce .and. & + validRetrievalMask(1:nPoints,1:nSubCols) + + ! ######################################################################################## + ! Use these as pixel counts at first + ! ######################################################################################## + Cloud_Fraction_Total_Mean(1:nPoints) = real(count(cloudMask, dim = 2)) + Cloud_Fraction_Water_Mean(1:nPoints) = real(count(waterCloudMask, dim = 2)) + Cloud_Fraction_Ice_Mean(1:nPoints) = real(count(iceCloudMask, dim = 2)) + Cloud_Fraction_High_Mean(1:nPoints) = real(count(cloudMask .and. cloud_top_pressure <= & + highCloudPressureLimit, dim = 2)) + Cloud_Fraction_Low_Mean(1:nPoints) = real(count(cloudMask .and. cloud_top_pressure > & + lowCloudPressureLimit, dim = 2)) + Cloud_Fraction_Mid_Mean(1:nPoints) = Cloud_Fraction_Total_Mean(1:nPoints) - Cloud_Fraction_High_Mean(1:nPoints)& + - Cloud_Fraction_Low_Mean(1:nPoints) + + ! ######################################################################################## + ! Compute column amounts. + ! ######################################################################################## + where(Cloud_Fraction_Total_Mean(1:nPoints) > 0) + Optical_Thickness_Total_Mean(1:nPoints) = sum(optical_thickness, mask = cloudMask, dim = 2) / & + Cloud_Fraction_Total_Mean(1:nPoints) + Optical_Thickness_Total_MeanLog10(1:nPoints) = sum(log10(abs(optical_thickness)), mask = cloudMask, & + dim = 2) / Cloud_Fraction_Total_Mean(1:nPoints) + elsewhere + Optical_Thickness_Total_Mean = R_UNDEF + Optical_Thickness_Total_MeanLog10 = R_UNDEF + endwhere + where(Cloud_Fraction_Water_Mean(1:nPoints) > 0) + Optical_Thickness_Water_Mean(1:nPoints) = sum(optical_thickness, mask = waterCloudMask, dim = 2) / & + Cloud_Fraction_Water_Mean(1:nPoints) + Liquid_Water_Path_Mean(1:nPoints) = LWP_conversion*sum(particle_size*optical_thickness, & + mask=waterCloudMask,dim=2)/Cloud_Fraction_Water_Mean(1:nPoints) + Optical_Thickness_Water_MeanLog10(1:nPoints) = sum(log10(abs(optical_thickness)), mask = waterCloudMask,& + dim = 2) / Cloud_Fraction_Water_Mean(1:nPoints) + Cloud_Particle_Size_Water_Mean(1:nPoints) = sum(particle_size, mask = waterCloudMask, dim = 2) / & + Cloud_Fraction_Water_Mean(1:nPoints) + elsewhere + Optical_Thickness_Water_Mean = R_UNDEF + Optical_Thickness_Water_MeanLog10 = R_UNDEF + Cloud_Particle_Size_Water_Mean = R_UNDEF + Liquid_Water_Path_Mean = R_UNDEF + endwhere + where(Cloud_Fraction_Ice_Mean(1:nPoints) > 0) + Optical_Thickness_Ice_Mean(1:nPoints) = sum(optical_thickness, mask = iceCloudMask, dim = 2) / & + Cloud_Fraction_Ice_Mean(1:nPoints) + Ice_Water_Path_Mean(1:nPoints) = LWP_conversion * ice_density*sum(particle_size*optical_thickness,& + mask=iceCloudMask,dim = 2) /Cloud_Fraction_Ice_Mean(1:nPoints) + Optical_Thickness_Ice_MeanLog10(1:nPoints) = sum(log10(abs(optical_thickness)), mask = iceCloudMask,& + dim = 2) / Cloud_Fraction_Ice_Mean(1:nPoints) + Cloud_Particle_Size_Ice_Mean(1:nPoints) = sum(particle_size, mask = iceCloudMask, dim = 2) / & + Cloud_Fraction_Ice_Mean(1:nPoints) + elsewhere + Optical_Thickness_Ice_Mean = R_UNDEF + Optical_Thickness_Ice_MeanLog10 = R_UNDEF + Cloud_Particle_Size_Ice_Mean = R_UNDEF + Ice_Water_Path_Mean = R_UNDEF + endwhere + Cloud_Top_Pressure_Total_Mean = sum(cloud_top_pressure, mask = cloudMask, dim = 2) / & + max(1, count(cloudMask, dim = 2)) + + ! ######################################################################################## + ! Normalize pixel counts to fraction. + ! ######################################################################################## + Cloud_Fraction_High_Mean(1:nPoints) = Cloud_Fraction_High_Mean(1:nPoints) /nSubcols + Cloud_Fraction_Mid_Mean(1:nPoints) = Cloud_Fraction_Mid_Mean(1:nPoints) /nSubcols + Cloud_Fraction_Low_Mean(1:nPoints) = Cloud_Fraction_Low_Mean(1:nPoints) /nSubcols + Cloud_Fraction_Total_Mean(1:nPoints) = Cloud_Fraction_Total_Mean(1:nPoints) /nSubcols + Cloud_Fraction_Ice_Mean(1:nPoints) = Cloud_Fraction_Ice_Mean(1:nPoints) /nSubcols + Cloud_Fraction_Water_Mean(1:nPoints) = Cloud_Fraction_Water_Mean(1:nPoints) /nSubcols + + ! ######################################################################################## + ! Joint histograms + ! ######################################################################################## + ! Loop over all points + tauWRK(1:nPoints,1:nSubCols) = optical_thickness(1:nPoints,1:nSubCols) + ctpWRK(1:nPoints,1:nSubCols) = cloud_top_pressure(1:nPoints,1:nSubCols) + reffIceWRK(1:nPoints,1:nSubCols) = merge(particle_size,R_UNDEF,iceCloudMask) + reffLiqWRK(1:nPoints,1:nSubCols) = merge(particle_size,R_UNDEF,waterCloudMask) + tauLiqWRK(1:nPoints,1:nSubCols) = merge(optical_thickness,R_UNDEF,waterCloudMask) + tauIceWRK(1:nPoints,1:nSubCols) = merge(optical_thickness,R_UNDEF,iceCloudMask) + lwpWRK(1:nPoints,1:nSubCols) = merge(LWP_conversion*particle_size*optical_thickness,R_UNDEF,waterCloudMask) + iwpWRK(1:nPoints,1:nSubCols) = merge(LWP_conversion*ice_density*particle_size*optical_thickness,R_UNDEF,iceCloudMask) + do j=1,nPoints + + ! Fill clear and optically thin subcolumns with fill + where(.not. cloudMask(j,1:nSubCols)) + tauWRK(j,1:nSubCols) = -999._wp + ctpWRK(j,1:nSubCols) = -999._wp + tauLiqWRK(j,1:nSubCols) = -999._wp + tauIceWRK(j,1:nSubCols) = -999._wp + lwpWRK(j,1:nSubCols) = -999._wp + iwpWRK(j,1:nSubCols) = -999._wp + endwhere + ! Joint histogram of tau/CTP + call hist2D(tauWRK(j,1:nSubCols),ctpWRK(j,1:nSubCols),nSubCols,& + modis_histTau,numMODISTauBins,& + modis_histPres,numMODISPresBins,& + Optical_Thickness_vs_Cloud_Top_Pressure(j,1:numMODISTauBins,1:numMODISPresBins)) + ! Joint histogram of tau/CTP for Liquid clouds + call hist2D(tauLiqWRK(j,1:nSubCols),ctpWRK(j,1:nSubCols),nSubCols,& + modis_histTau,numMODISTauBins,& + modis_histPres,numMODISPresBins,& + Optical_Thickness_vs_Cloud_Top_Pressure_Liq(j,1:numMODISTauBins,1:numMODISPresBins)) + ! Joint histogram of tau/CTP for Ice clouds + call hist2D(tauIceWRK(j,1:nSubCols),ctpWRK(j,1:nSubCols),nSubCols,& + modis_histTau,numMODISTauBins,& + modis_histPres,numMODISPresBins,& + Optical_Thickness_vs_Cloud_Top_Pressure_Ice(j,1:numMODISTauBins,1:numMODISPresBins)) + ! Joint histogram of LWP/ReffLiq + call hist2D(lwpWRK(j,1:nSubCols),reffLiqWRK(j,1:nSubCols),nSubCols, & + modis_histLWP,numMODISLWPBins,modis_histReffLiq, & + numMODISReffLiqBins, LWP_vs_ReffLiq(j,1:numMODISLWPBins,1:numMODISReffLiqBins)) + ! Joint histogram of IWP/ReffIce + call hist2D(iwpWRK(j,1:nSubCols),reffIceWRK(j,1:nSubCols),nSubCols, & + modis_histIWP,numMODISIWPBins,modis_histReffIce, & + numMODISReffIceBins, IWP_vs_ReffIce(j,1:numMODISIWPBins,1:numMODISReffIceBins)) + ! Joint histogram of tau/ReffICE + call hist2D(tauWRK(j,1:nSubCols),reffIceWrk(j,1:nSubCols),nSubCols, & + modis_histTau,numMODISTauBins,modis_histReffIce, & + numMODISReffIceBins, Optical_Thickness_vs_ReffIce(j,1:numMODISTauBins,1:numMODISReffIceBins)) + ! Joint histogram of tau/ReffLIQ + call hist2D(tauWRK(j,1:nSubCols),reffLiqWrk(j,1:nSubCols),nSubCols, & + modis_histTau,numMODISTauBins,modis_histReffLiq, & + numMODISReffLiqBins, Optical_Thickness_vs_ReffLiq(j,1:numMODISTauBins,1:numMODISReffLiqBins)) + + enddo + Optical_Thickness_vs_Cloud_Top_Pressure(1:nPoints,1:numMODISTauBins,1:numMODISPresBins) = & + Optical_Thickness_vs_Cloud_Top_Pressure(1:nPoints,1:numMODISTauBins,1:numMODISPresBins)/nSubCols + Optical_Thickness_vs_Cloud_Top_Pressure_Liq(1:nPoints,1:numMODISTauBins,1:numMODISPresBins) = & + Optical_Thickness_vs_Cloud_Top_Pressure_Liq(1:nPoints,1:numMODISTauBins,1:numMODISPresBins)/nSubCols + Optical_Thickness_vs_Cloud_Top_Pressure_Ice(1:nPoints,1:numMODISTauBins,1:numMODISPresBins) = & + Optical_Thickness_vs_Cloud_Top_Pressure_Ice(1:nPoints,1:numMODISTauBins,1:numMODISPresBins)/nSubCols + LWP_vs_ReffLiq(1:nPoints,1:numMODISLWPBins,1:numMODISReffLiqBins) = & + LWP_vs_ReffLiq(1:nPoints,1:numMODISLWPBins,1:numMODISReffLiqBins)/nSubCols + IWP_vs_ReffIce(1:nPoints,1:numMODISIWPBins,1:numMODISReffIceBins) = & + IWP_vs_ReffIce(1:nPoints,1:numMODISIWPBins,1:numMODISReffIceBins)/nSubCols + Optical_Thickness_vs_ReffIce(1:nPoints,1:numMODISTauBins,1:numMODISReffIceBins) = & + Optical_Thickness_vs_ReffIce(1:nPoints,1:numMODISTauBins,1:numMODISReffIceBins)/nSubCols + Optical_Thickness_vs_ReffLiq(1:nPoints,1:numMODISTauBins,1:numMODISReffLiqBins) = & + Optical_Thickness_vs_ReffLiq(1:nPoints,1:numMODISTauBins,1:numMODISReffLiqBins)/nSubCols + + + ! Unit conversion + where(Optical_Thickness_vs_Cloud_Top_Pressure /= R_UNDEF) & + Optical_Thickness_vs_Cloud_Top_Pressure = Optical_Thickness_vs_Cloud_Top_Pressure*100._wp + where(Optical_Thickness_vs_Cloud_Top_Pressure_Liq /= R_UNDEF) & + Optical_Thickness_vs_Cloud_Top_Pressure_Liq = Optical_Thickness_vs_Cloud_Top_Pressure_Liq*100._wp + where(Optical_Thickness_vs_Cloud_Top_Pressure_Ice /= R_UNDEF) & + Optical_Thickness_vs_Cloud_Top_Pressure_Ice = Optical_Thickness_vs_Cloud_Top_Pressure_Ice*100._wp + where(LWP_vs_ReffLiq /= R_UNDEF) LWP_vs_ReffLiq = LWP_vs_ReffLiq*100._wp + where(IWP_vs_ReffIce /= R_UNDEF) IWP_vs_ReffIce = IWP_vs_ReffIce*100._wp + where(Optical_Thickness_vs_ReffIce /= R_UNDEF) Optical_Thickness_vs_ReffIce = Optical_Thickness_vs_ReffIce*100._wp + where(Optical_Thickness_vs_ReffLiq /= R_UNDEF) Optical_Thickness_vs_ReffLiq = Optical_Thickness_vs_ReffLiq*100._wp + where(Cloud_Fraction_Total_Mean /= R_UNDEF) Cloud_Fraction_Total_Mean = Cloud_Fraction_Total_Mean*100._wp + where(Cloud_Fraction_Water_Mean /= R_UNDEF) Cloud_Fraction_Water_Mean = Cloud_Fraction_Water_Mean*100._wp + where(Cloud_Fraction_Ice_Mean /= R_UNDEF) Cloud_Fraction_Ice_Mean = Cloud_Fraction_Ice_Mean*100._wp + where(Cloud_Fraction_High_Mean /= R_UNDEF) Cloud_Fraction_High_Mean = Cloud_Fraction_High_Mean*100._wp + where(Cloud_Fraction_Mid_Mean /= R_UNDEF) Cloud_Fraction_Mid_Mean = Cloud_Fraction_Mid_Mean*100._wp + where(Cloud_Fraction_Low_Mean /= R_UNDEF) Cloud_Fraction_Low_Mean = Cloud_Fraction_Low_Mean*100._wp + + end subroutine modis_column + + ! ######################################################################################## + function cloud_top_pressure(nLevels,tauIncrement, pressure, tauLimit) + ! INPUTS + integer, intent(in) :: nLevels + real(wp),intent(in),dimension(nLevels) :: tauIncrement, pressure + real(wp),intent(in) :: tauLimit + ! OUTPUTS + real(wp) :: cloud_top_pressure + ! LOCAL VARIABLES + real(wp) :: deltaX, totalTau, totalProduct + integer :: i + + ! Find the extinction-weighted pressure. Assume that pressure varies linearly between + ! layers and use the trapezoidal rule. + totalTau = 0._wp; totalProduct = 0._wp + do i = 2, size(tauIncrement) + if(totalTau + tauIncrement(i) > tauLimit) then + deltaX = tauLimit - totalTau + totalTau = totalTau + deltaX + ! + ! Result for trapezoidal rule when you take less than a full step + ! tauIncrement is a layer-integrated value + ! + totalProduct = totalProduct & + + pressure(i-1) * deltaX & + + (pressure(i) - pressure(i-1)) * deltaX**2/(2._wp * tauIncrement(i)) + else + totalTau = totalTau + tauIncrement(i) + totalProduct = totalProduct + tauIncrement(i) * (pressure(i) + pressure(i-1)) / 2._wp + end if + if(totalTau >= tauLimit) exit + end do + + if (totalTau > 0._wp) then + cloud_top_pressure = totalProduct/totalTau + else + cloud_top_pressure = 0._wp + endif + + end function cloud_top_pressure + + ! ######################################################################################## + function weight_by_extinction(nLevels,tauIncrement, f, tauLimit) + ! INPUTS + integer, intent(in) :: nLevels + real(wp),intent(in),dimension(nLevels) :: tauIncrement, f + real(wp),intent(in) :: tauLimit + ! OUTPUTS + real(wp) :: weight_by_extinction + ! LOCAL VARIABLES + real(wp) :: deltaX, totalTau, totalProduct + integer :: i + + ! Find the extinction-weighted value of f(tau), assuming constant f within each layer + totalTau = 0._wp; totalProduct = 0._wp + do i = 1, size(tauIncrement) + if(totalTau + tauIncrement(i) > tauLimit) then + deltaX = tauLimit - totalTau + totalTau = totalTau + deltaX + totalProduct = totalProduct + deltaX * f(i) + else + totalTau = totalTau + tauIncrement(i) + totalProduct = totalProduct + tauIncrement(i) * f(i) + end if + if(totalTau >= tauLimit) exit + end do + + if (totalTau > 0._wp) then + weight_by_extinction = totalProduct/totalTau + else + weight_by_extinction = 0._wp + endif + + end function weight_by_extinction + + ! ######################################################################################## + pure function interpolate_to_min(x, y, yobs) + ! INPUTS + real(wp),intent(in),dimension(num_trial_res) :: x, y + real(wp),intent(in) :: yobs + ! OUTPUTS + real(wp) :: interpolate_to_min + ! LOCAL VARIABLES + real(wp), dimension(num_trial_res) :: diff + integer :: nPoints, minDiffLoc, lowerBound, upperBound + + ! Given a set of values of y as y(x), find the value of x that minimizes abs(y - yobs) + ! y must be monotonic in x + + nPoints = size(y) + diff(1:num_trial_res) = y(1:num_trial_res) - yobs + minDiffLoc = minloc(abs(diff), dim = 1) + + if(minDiffLoc == 1) then + lowerBound = minDiffLoc + upperBound = minDiffLoc + 1 + else if(minDiffLoc == nPoints) then + lowerBound = minDiffLoc - 1 + upperBound = minDiffLoc + else + if(diff(minDiffLoc-1) * diff(minDiffLoc) < 0) then + lowerBound = minDiffLoc-1 + upperBound = minDiffLoc + else + lowerBound = minDiffLoc + upperBound = minDiffLoc + 1 + end if + end if + + if(diff(lowerBound) * diff(upperBound) < 0) then + ! + ! Interpolate the root position linearly if we bracket the root + ! + interpolate_to_min = x(upperBound) - & + diff(upperBound) * (x(upperBound) - x(lowerBound)) / (diff(upperBound) - diff(lowerBound)) + else + interpolate_to_min = re_fill + end if + + + end function interpolate_to_min + + ! ######################################################################################## + ! Optical properties + ! ######################################################################################## + elemental function get_g_nir_old (phase, re) + ! Polynomial fit for asummetry parameter g in MODIS band 7 (near IR) as a function + ! of size for ice and water + ! Fits from Steve Platnick + + ! INPUTS + integer, intent(in) :: phase + real(wp),intent(in) :: re + ! OUTPUTS + real(wp) :: get_g_nir_old + ! LOCAL VARIABLES(parameters) + real(wp), dimension(3), parameter :: & + ice_coefficients = (/ 0.7432, 4.5563e-3, -2.8697e-5 /), & + small_water_coefficients = (/ 0.8027, -1.0496e-2, 1.7071e-3 /), & + big_water_coefficients = (/ 0.7931, 5.3087e-3, -7.4995e-5 /) + + ! approx. fits from MODIS Collection 5 LUT scattering calculations + if(phase == phaseIsLiquid) then + if(re < 8.) then + get_g_nir_old = fit_to_quadratic(re, small_water_coefficients) + if(re < re_water_min) get_g_nir_old = fit_to_quadratic(re_water_min, small_water_coefficients) + else + get_g_nir_old = fit_to_quadratic(re, big_water_coefficients) + if(re > re_water_max) get_g_nir_old = fit_to_quadratic(re_water_max, big_water_coefficients) + end if + else + get_g_nir_old = fit_to_quadratic(re, ice_coefficients) + if(re < re_ice_min) get_g_nir_old = fit_to_quadratic(re_ice_min, ice_coefficients) + if(re > re_ice_max) get_g_nir_old = fit_to_quadratic(re_ice_max, ice_coefficients) + end if + + end function get_g_nir_old + + ! ######################################################################################## + elemental function get_ssa_nir_old (phase, re) + ! Polynomial fit for single scattering albedo in MODIS band 7 (near IR) as a function + ! of size for ice and water + ! Fits from Steve Platnick + + ! INPUTS + integer, intent(in) :: phase + real(wp),intent(in) :: re + ! OUTPUTS + real(wp) :: get_ssa_nir_old + ! LOCAL VARIABLES (parameters) + real(wp), dimension(4), parameter :: ice_coefficients = (/ 0.9994, -4.5199e-3, 3.9370e-5, -1.5235e-7 /) + real(wp), dimension(3), parameter :: water_coefficients = (/ 1.0008, -2.5626e-3, 1.6024e-5 /) + + ! approx. fits from MODIS Collection 5 LUT scattering calculations + if(phase == phaseIsLiquid) then + get_ssa_nir_old = fit_to_quadratic(re, water_coefficients) + if(re < re_water_min) get_ssa_nir_old = fit_to_quadratic(re_water_min, water_coefficients) + if(re > re_water_max) get_ssa_nir_old = fit_to_quadratic(re_water_max, water_coefficients) + else + get_ssa_nir_old = fit_to_cubic(re, ice_coefficients) + if(re < re_ice_min) get_ssa_nir_old = fit_to_cubic(re_ice_min, ice_coefficients) + if(re > re_ice_max) get_ssa_nir_old = fit_to_cubic(re_ice_max, ice_coefficients) + end if + + end function get_ssa_nir_old + + elemental function get_g_nir (phase, re) + ! + ! Polynomial fit for asummetry parameter g in MODIS band 7 (near IR) as a function + ! of size for ice and water + ! Fits from Steve Platnick + ! + + integer, intent(in) :: phase + real(wp), intent(in) :: re + real(wp) :: get_g_nir + + real(wp), dimension(3), parameter :: ice_coefficients = (/ 0.7490, 6.5153e-3, -5.4136e-5 /), & + small_water_coefficients = (/ 1.0364, -8.8800e-2, 7.0000e-3 /) + real(wp), dimension(4), parameter :: big_water_coefficients = (/ 0.6035, 2.8993e-2, -1.1051e-3, 1.5134e-5 /) + + ! approx. fits from MODIS Collection 6 LUT scattering calculations for 3.7 µm channel size retrievals + if(phase == phaseIsLiquid) then + if(re < 7.) then + get_g_nir = fit_to_quadratic(re, small_water_coefficients) + if(re < re_water_min) get_g_nir = fit_to_quadratic(re_water_min, small_water_coefficients) + else + get_g_nir = fit_to_cubic(re, big_water_coefficients) + if(re > re_water_max) get_g_nir = fit_to_cubic(re_water_max, big_water_coefficients) + end if + else + get_g_nir = fit_to_quadratic(re, ice_coefficients) + if(re < re_ice_min) get_g_nir = fit_to_quadratic(re_ice_min, ice_coefficients) + if(re > re_ice_max) get_g_nir = fit_to_quadratic(re_ice_max, ice_coefficients) + end if + + end function get_g_nir + + ! -------------------------------------------- + elemental function get_ssa_nir (phase, re) + integer, intent(in) :: phase + real(wp), intent(in) :: re + real(wp) :: get_ssa_nir + ! + ! Polynomial fit for single scattering albedo in MODIS band 7 (near IR) as a function + ! of size for ice and water + ! Fits from Steve Platnick + ! + real(wp), dimension(4), parameter :: ice_coefficients = (/ 0.9625, -1.8069e-2, 3.3281e-4,-2.2865e-6/) + real(wp), dimension(3), parameter :: water_coefficients = (/ 1.0044, -1.1397e-2, 1.3300e-4 /) + + ! approx. fits from MODIS Collection 6 LUT scattering calculations + if(phase == phaseIsLiquid) then + get_ssa_nir = fit_to_quadratic(re, water_coefficients) + if(re < re_water_min) get_ssa_nir = fit_to_quadratic(re_water_min, water_coefficients) + if(re > re_water_max) get_ssa_nir = fit_to_quadratic(re_water_max, water_coefficients) + else + get_ssa_nir = fit_to_cubic(re, ice_coefficients) + if(re < re_ice_min) get_ssa_nir = fit_to_cubic(re_ice_min, ice_coefficients) + if(re > re_ice_max) get_ssa_nir = fit_to_cubic(re_ice_max, ice_coefficients) + end if + + end function get_ssa_nir + + + + ! ######################################################################################## + pure function fit_to_cubic(x, coefficients) + ! INPUTS + real(wp), intent(in) :: x + real(wp), dimension(4), intent(in) :: coefficients + ! OUTPUTS + real(wp) :: fit_to_cubic + + fit_to_cubic = coefficients(1) + x * (coefficients(2) + x * (coefficients(3) + x * coefficients(4))) + end function fit_to_cubic + + ! ######################################################################################## + pure function fit_to_quadratic(x, coefficients) + ! INPUTS + real(wp), intent(in) :: x + real(wp), dimension(3), intent(in) :: coefficients + ! OUTPUTS + real(wp) :: fit_to_quadratic + + fit_to_quadratic = coefficients(1) + x * (coefficients(2) + x * (coefficients(3))) + end function fit_to_quadratic + + ! ######################################################################################## + ! Radiative transfer + ! ######################################################################################## + pure function compute_toa_reflectace(nLevels,tau, g, w0) + ! This wrapper reports reflectance only and strips out non-cloudy elements from the + ! calculation + + ! INPUTS + integer,intent(in) :: nLevels + real(wp),intent(in),dimension(nLevels) :: tau, g, w0 + ! OUTPUTS + real(wp) :: compute_toa_reflectace + ! LOCAL VARIABLES + logical, dimension(nLevels) :: cloudMask + integer, dimension(count(tau(1:nLevels) > 0)) :: cloudIndicies + real(wp),dimension(count(tau(1:nLevels) > 0)) :: Refl,Trans + real(wp) :: Refl_tot, Trans_tot + integer :: i + + cloudMask(1:nLevels) = tau(1:nLevels) > 0. + cloudIndicies = pack((/ (i, i = 1, nLevels) /), mask = cloudMask) + do i = 1, size(cloudIndicies) + call two_stream(tau(cloudIndicies(i)), g(cloudIndicies(i)), w0(cloudIndicies(i)), Refl(i), Trans(i)) + end do + + call adding_doubling(count(tau(1:nLevels) > 0),Refl(:), Trans(:), Refl_tot, Trans_tot) + + compute_toa_reflectace = Refl_tot + + end function compute_toa_reflectace + + ! ######################################################################################## + pure subroutine two_stream(tauint, gint, w0int, ref, tra) + ! Compute reflectance in a single layer using the two stream approximation + ! The code itself is from Lazaros Oreopoulos via Steve Platnick + ! INPUTS + real(wp), intent(in) :: tauint, gint, w0int + ! OUTPUTS + real(wp), intent(out) :: ref, tra + ! LOCAL VARIABLES + ! for delta Eddington code + ! xmu, gamma3, and gamma4 only used for collimated beam approximation (i.e., beam=1) + integer, parameter :: beam = 2 + real(wp),parameter :: xmu = 0.866, minConservativeW0 = 0.9999999 + real(wp) :: tau, w0, g, f, gamma1, gamma2, gamma3, gamma4, & + rh, a1, a2, rk, r1, r2, r3, r4, r5, t1, t2, t3, t4, t5, beta, e1, e2, ef1, ef2, den, th + + ! Compute reflectance and transmittance in a single layer using the two stream approximation + ! The code itself is from Lazaros Oreopoulos via Steve Platnick + f = gint**2 + tau = (1._wp - w0int * f) * tauint + w0 = (1._wp - f) * w0int / (1._wp - w0int * f) + g = (gint - f) / (1._wp - f) + + ! delta-Eddington (Joseph et al. 1976) + gamma1 = (7._wp - w0* (4._wp + 3._wp * g)) / 4._wp + gamma2 = -(1._wp - w0* (4._wp - 3._wp * g)) / 4._wp + gamma3 = (2._wp - 3._wp*g*xmu) / 4._wp + gamma4 = 1._wp - gamma3 + + if (w0int > minConservativeW0) then + ! Conservative scattering + if (beam == 1) then + rh = (gamma1*tau+(gamma3-gamma1*xmu)*(1-exp(-tau/xmu))) + + ref = rh / (1._wp + gamma1 * tau) + tra = 1._wp - ref + else if(beam == 2) then + ref = gamma1*tau/(1._wp + gamma1*tau) + tra = 1._wp - ref + endif + else + ! Non-conservative scattering + a1 = gamma1 * gamma4 + gamma2 * gamma3 + a2 = gamma1 * gamma3 + gamma2 * gamma4 + + rk = sqrt(gamma1**2 - gamma2**2) + + r1 = (1._wp - rk * xmu) * (a2 + rk * gamma3) + r2 = (1._wp + rk * xmu) * (a2 - rk * gamma3) + r3 = 2._wp * rk *(gamma3 - a2 * xmu) + r4 = (1._wp - (rk * xmu)**2) * (rk + gamma1) + r5 = (1._wp - (rk * xmu)**2) * (rk - gamma1) + + t1 = (1._wp + rk * xmu) * (a1 + rk * gamma4) + t2 = (1._wp - rk * xmu) * (a1 - rk * gamma4) + t3 = 2._wp * rk * (gamma4 + a1 * xmu) + t4 = r4 + t5 = r5 + + beta = -r5 / r4 + + e1 = min(rk * tau, 500._wp) + e2 = min(tau / xmu, 500._wp) + + if (beam == 1) then + den = r4 * exp(e1) + r5 * exp(-e1) + ref = w0*(r1*exp(e1)-r2*exp(-e1)-r3*exp(-e2))/den + den = t4 * exp(e1) + t5 * exp(-e1) + th = exp(-e2) + tra = th-th*w0*(t1*exp(e1)-t2*exp(-e1)-t3*exp(e2))/den + elseif (beam == 2) then + ef1 = exp(-e1) + ef2 = exp(-2*e1) + ref = (gamma2*(1._wp-ef2))/((rk+gamma1)*(1._wp-beta*ef2)) + tra = (2._wp*rk*ef1)/((rk+gamma1)*(1._wp-beta*ef2)) + endif + end if + end subroutine two_stream + + ! ######################################################################################## + elemental function two_stream_reflectance(tauint, gint, w0int) + ! Compute reflectance in a single layer using the two stream approximation + ! The code itself is from Lazaros Oreopoulos via Steve Platnick + + ! INPUTS + real(wp), intent(in) :: tauint, gint, w0int + ! OUTPUTS + real(wp) :: two_stream_reflectance + ! LOCAL VARIABLES + ! for delta Eddington code + ! xmu, gamma3, and gamma4 only used for collimated beam approximation (i.e., beam=1) + integer, parameter :: beam = 2 + real(wp),parameter :: xmu = 0.866, minConservativeW0 = 0.9999999 + real(wp) :: tau, w0, g, f, gamma1, gamma2, gamma3, gamma4, & + rh, a1, a2, rk, r1, r2, r3, r4, r5, t1, t2, t3, t4, t5, beta, e1, e2, ef1, ef2, den + + f = gint**2 + tau = (1._wp - w0int * f) * tauint + w0 = (1._wp - f) * w0int / (1._wp - w0int * f) + g = (gint - f) / (1._wp - f) + + ! delta-Eddington (Joseph et al. 1976) + gamma1 = (7._wp - w0* (4._wp + 3._wp * g)) / 4._wp + gamma2 = -(1._wp - w0* (4._wp - 3._wp * g)) / 4._wp + gamma3 = (2._wp - 3._wp*g*xmu) / 4._wp + gamma4 = 1._wp - gamma3 + + if (w0int > minConservativeW0) then + ! Conservative scattering + if (beam == 1) then + rh = (gamma1*tau+(gamma3-gamma1*xmu)*(1-exp(-tau/xmu))) + two_stream_reflectance = rh / (1._wp + gamma1 * tau) + elseif (beam == 2) then + two_stream_reflectance = gamma1*tau/(1._wp + gamma1*tau) + endif + + else ! + + ! Non-conservative scattering + a1 = gamma1 * gamma4 + gamma2 * gamma3 + a2 = gamma1 * gamma3 + gamma2 * gamma4 + + rk = sqrt(gamma1**2 - gamma2**2) + + r1 = (1._wp - rk * xmu) * (a2 + rk * gamma3) + r2 = (1._wp + rk * xmu) * (a2 - rk * gamma3) + r3 = 2._wp * rk *(gamma3 - a2 * xmu) + r4 = (1._wp - (rk * xmu)**2) * (rk + gamma1) + r5 = (1._wp - (rk * xmu)**2) * (rk - gamma1) + + t1 = (1._wp + rk * xmu) * (a1 + rk * gamma4) + t2 = (1._wp - rk * xmu) * (a1 - rk * gamma4) + t3 = 2._wp * rk * (gamma4 + a1 * xmu) + t4 = r4 + t5 = r5 + + beta = -r5 / r4 + + e1 = min(rk * tau, 500._wp) + e2 = min(tau / xmu, 500._wp) + + if (beam == 1) then + den = r4 * exp(e1) + r5 * exp(-e1) + two_stream_reflectance = w0*(r1*exp(e1)-r2*exp(-e1)-r3*exp(-e2))/den + elseif (beam == 2) then + ef1 = exp(-e1) + ef2 = exp(-2*e1) + two_stream_reflectance = (gamma2*(1._wp-ef2))/((rk+gamma1)*(1._wp-beta*ef2)) + endif + + end if + end function two_stream_reflectance + + ! ######################################################################################## + pure subroutine adding_doubling (npts,Refl, Tran, Refl_tot, Tran_tot) + ! Use adding/doubling formulas to compute total reflectance and transmittance from + ! layer values + + ! INPUTS + integer,intent(in) :: npts + real(wp),intent(in),dimension(npts) :: Refl,Tran + ! OUTPUTS + real(wp),intent(out) :: Refl_tot, Tran_tot + ! LOCAL VARIABLES + integer :: i + real(wp), dimension(npts) :: Refl_cumulative, Tran_cumulative + + Refl_cumulative(1) = Refl(1) + Tran_cumulative(1) = Tran(1) + + do i=2, npts + ! place (add) previous combined layer(s) reflectance on top of layer i, w/black surface (or ignoring surface): + Refl_cumulative(i) = Refl_cumulative(i-1) + Refl(i)*(Tran_cumulative(i-1)**2)/(1._wp - Refl_cumulative(i-1) * Refl(i)) + Tran_cumulative(i) = (Tran_cumulative(i-1)*Tran(i)) / (1._wp - Refl_cumulative(i-1) * Refl(i)) + end do + + Refl_tot = Refl_cumulative(size(Refl)) + Tran_tot = Tran_cumulative(size(Refl)) + + end subroutine adding_doubling + +end module mod_modis_sim From d64970365ea2c312885f01d8547208bcfba066cf Mon Sep 17 00:00:00 2001 From: zyuying Date: Thu, 9 May 2024 16:33:10 -0700 Subject: [PATCH 161/388] Add files via upload --- .../src/physics/cam/cospsimulator_intr.F90 | 128 +++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/components/eam/src/physics/cam/cospsimulator_intr.F90 b/components/eam/src/physics/cam/cospsimulator_intr.F90 index 213b3d627b6..663278e804c 100644 --- a/components/eam/src/physics/cam/cospsimulator_intr.F90 +++ b/components/eam/src/physics/cam/cospsimulator_intr.F90 @@ -29,6 +29,8 @@ module cospsimulator_intr numMODISTauBins, numMODISPresBins, numMODISReffIceBins, numMODISReffLiqBins, & numISCCPTauBins, numISCCPPresBins, numMISRTauBins, reffICE_binEdges, & reffICE_binCenters, reffLIQ_binEdges, reffLIQ_binCenters, LIDAR_NTYPE, & + numMODISLWPBins, numMODISIWPBins, LWP_binCenters, LWP_binEdges, & + IWP_binCenters, IWP_binEdges, & LIDAR_PHASE_TEMP,LIDAR_PHASE_TEMP_BNDS, & nCloudsatPrecipClass, & nsza_cosp => PARASOL_NREFL, & @@ -97,6 +99,10 @@ module cospsimulator_intr real(r8), target :: reffLIQ_binEdges_cosp(2,numMODISReffLiqBins) real(r8), target :: reffICE_binCenters_cosp(numMODISReffIceBins) real(r8), target :: reffLIQ_binCenters_cosp(numMODISReffLiqBins) + real(r8), target :: LWP_binEdges_cosp(2,numMODISLWPBins) + real(r8), target :: IWP_binEdges_cosp(2,numMODISIWPBins) + real(r8), target :: LWP_binCenters_cosp(numMODISLWPBins) + real(r8), target :: IWP_binCenters_cosp(numMODISIWPBins) real(r8) :: htmlmid_cosp(nhtml_cosp) ! Model level height midpoints for output integer :: prstau_cosp(nprs_cosp*ntau_cosp) ! ISCCP mixed output dimension index @@ -311,7 +317,11 @@ subroutine setcosp2values(Nlr_in,use_vgrid_in,csat_vgrid_in,Ncolumns_in,cosp_nra reffICE_binEdges_cosp = reffICE_binEdges reffLIQ_binCenters_cosp = reffLIQ_binCenters reffLIQ_binEdges_cosp = reffLIQ_binEdges - + LWP_binCenters_cosp = LWP_binCenters + LWP_binEdges_cosp = LWP_binEdges + IWP_binCenters_cosp = IWP_binCenters + IWP_binEdges_cosp = IWP_binEdges + ! Initialize the distributional parameters for hydrometeors in radar simulator. In COSPv1.4, this was declared in ! cosp_defs.f. if (cloudsat_micro_scheme == 'MMF_v3.5_two_moment') then @@ -676,6 +686,12 @@ subroutine cospsimulator_intr_register() call add_hist_coord('cosp_reffliq',numMODISReffLiqBins, & 'COSP Mean MODIS effective radius (liquid)', 'm', reffLIQ_binCenters_cosp, & bounds_name='cosp_reffliq_bnds',bounds=reffLIQ_binEdges_cosp) + call add_hist_coord('cosp_iwp_modis',numMODISIWPBins, & + 'COSP Mean MODIS ice water path (ice)', 'kg/m2', IWP_binCenters_cosp, & + bounds_name='cosp_iwp_modis_bnds',bounds=IWP_binEdges_cosp) + call add_hist_coord('cosp_lwp_modis',numMODISLWPBins, & + 'COSP Mean MODIS liquid water path (liquid)', 'kg/m2', LWP_binCenters_cosp, & + bounds_name='cosp_lwp_modis_bnds',bounds=LWP_binEdges_cosp) end if #endif @@ -1045,12 +1061,24 @@ subroutine cospsimulator_intr_init() ! float clmodis ( time, plev, tau, loc ) call addfld ('CLMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & flag_xyfill=.true., fill_value=R_UNDEF) + ! float clliqmodis ( time, plev, tau, loc ) + call addfld ('CLLIQMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & + flag_xyfill=.true., fill_value=R_UNDEF) + ! float clicemodis ( time, plev, tau, loc ) + call addfld ('CLICEMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & + flag_xyfill=.true., fill_value=R_UNDEF) ! float clrimodis ( time, plev, tau, loc ) call addfld ('CLRIMODIS',(/'cosp_tau_modis','cosp_reffice '/),'A','%','MODIS Cloud Area Fraction', & flag_xyfill=.true., fill_value=R_UNDEF) ! float clrlmodis ( time, plev, tau, loc ) call addfld ('CLRLMODIS',(/'cosp_tau_modis','cosp_reffliq '/),'A','%','MODIS Cloud Area Fraction', & flag_xyfill=.true., fill_value=R_UNDEF) + ! float iwprimodis ( time, reffice, iwp, loc ) + call addfld ('IWPRIMODIS',(/'cosp_iwp_modis','cosp_reffice '/),'A','%','MODIS Cloud Area Fraction', & + flag_xyfill=.true., fill_value=R_UNDEF) + ! float lwprlmodis ( time, reffliq, lwp, loc ) + call addfld ('LWPRLMODIS',(/'cosp_lwp_modis','cosp_reffliq '/),'A','%','MODIS Cloud Area Fraction', & + flag_xyfill=.true., fill_value=R_UNDEF) !! add MODIS output to history file specified by the CAM namelist variable cosp_histfile_num call add_default ('CLTMODIS',cosp_histfile_num,' ') @@ -1076,6 +1104,8 @@ subroutine cospsimulator_intr_init() call add_default ('CLMODIS',cosp_histfile_num,' ') call add_default ('CLRIMODIS',cosp_histfile_num,' ') call add_default ('CLRLMODIS',cosp_histfile_num,' ') + call add_default ('IWPRIMODIS',cosp_histfile_num,' ') + call add_default ('LWPRLMODIS',cosp_histfile_num,' ') end if ! SUB-COLUMN OUTPUT @@ -1369,7 +1399,7 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn integer, parameter :: nf_calipso=28 ! number of calipso outputs integer, parameter :: nf_isccp=9 ! number of isccp outputs integer, parameter :: nf_misr=1 ! number of misr outputs - integer, parameter :: nf_modis=23 ! number of modis outputs + integer, parameter :: nf_modis=27 ! number of modis outputs ! Cloudsat outputs character(len=max_fieldname_len),dimension(nf_radar),parameter :: & @@ -1409,7 +1439,7 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn 'CLLMODIS ','TAUTMODIS ','TAUWMODIS ','TAUIMODIS ','TAUTLOGMODIS',& 'TAUWLOGMODIS','TAUILOGMODIS','REFFCLWMODIS','REFFCLIMODIS',& 'PCTMODIS ','LWPMODIS ','IWPMODIS ','CLMODIS ','CLRIMODIS ',& - 'CLRLMODIS '/) + 'CLRLMODIS ','LWPRLMODIS ','IWPRIMODIS ','CLLIQMODIS ','CLICEMODIS '/) logical :: run_radar(nf_radar,pcols) ! logical telling you if you should run radar simulator logical :: run_calipso(nf_calipso,pcols) ! logical telling you if you should run calipso simulator @@ -1569,10 +1599,18 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn real(r8) :: iwpmodis(pcols) real(r8) :: clmodis_cam(pcols,ntau_cosp_modis*nprs_cosp) real(r8) :: clmodis(pcols,ntau_cosp_modis,nprs_cosp) + real(r8) :: clliqmodis_cam(pcols,ntau_cosp_modis*nprs_cosp) + real(r8) :: clliqmodis(pcols,ntau_cosp_modis,nprs_cosp) + real(r8) :: clicemodis_cam(pcols,ntau_cosp_modis*nprs_cosp) + real(r8) :: clicemodis(pcols,ntau_cosp_modis,nprs_cosp) real(r8) :: clrimodis_cam(pcols,ntau_cosp*numMODISReffIceBins) real(r8) :: clrimodis(pcols,ntau_cosp,numMODISReffIceBins) real(r8) :: clrlmodis_cam(pcols,ntau_cosp*numMODISReffLiqBins) real(r8) :: clrlmodis(pcols,ntau_cosp,numMODISReffLiqBins) + real(r8) :: iwprimodis_cam(pcols,numMODISIWPBins*numMODISReffIceBins) + real(r8) :: iwprimodis(pcols,numMODISIWPBins,numMODISReffIceBins) + real(r8) :: lwprlmodis_cam(pcols,numMODISLWPBins*numMODISReffLiqBins) + real(r8) :: lwprlmodis(pcols,numMODISLWPBins,numMODISReffLiqBins) !real(r8) :: tau067_out(pcols,nhtml_cosp*nscol_cosp),emis11_out(pcols,nhtml_cosp*nscol_cosp) real(r8),dimension(pcols,nhtml_cosp*nscol_cosp) :: & tau067_out,emis11_out,fracliq_out,cal_betatot,cal_betatot_ice, & @@ -1710,10 +1748,18 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn iwpmodis(1:pcols) = R_UNDEF clmodis_cam(1:pcols,1:ntau_cosp_modis*nprs_cosp) = R_UNDEF clmodis(1:pcols,1:ntau_cosp_modis,1:nprs_cosp) = R_UNDEF + clliqmodis_cam(1:pcols,1:ntau_cosp_modis*nprs_cosp) = R_UNDEF + clliqmodis(1:pcols,1:ntau_cosp_modis,1:nprs_cosp) = R_UNDEF + clicemodis_cam(1:pcols,1:ntau_cosp_modis*nprs_cosp) = R_UNDEF + clicemodis(1:pcols,1:ntau_cosp_modis,1:nprs_cosp) = R_UNDEF clrimodis_cam(1:pcols,1:ntau_cosp_modis*numMODISReffIceBins) = R_UNDEF ! +cosp2 clrimodis(1:pcols,1:ntau_cosp_modis,1:numMODISReffIceBins) = R_UNDEF ! +cosp2 clrlmodis_cam(1:pcols,1:ntau_cosp_modis*numMODISReffLiqBins) = R_UNDEF ! +cosp2 clrlmodis(1:pcols,1:ntau_cosp_modis,1:numMODISReffLiqBins) = R_UNDEF ! +cosp2 + iwprimodis_cam(1:pcols,1:numMODISIWPBins*numMODISReffIceBins) = R_UNDEF ! +cosp2 + iwprimodis(1:pcols,1:numMODISIWPBins,1:numMODISReffIceBins) = R_UNDEF ! +cosp2 + lwprlmodis_cam(1:pcols,1:numMODISLWPBins*numMODISReffLiqBins) = R_UNDEF ! +cosp2 + lwprlmodis(1:pcols,1:numMODISLWPBins,1:numMODISReffLiqBins) = R_UNDEF ! +cosp2 tau067_out(1:pcols,1:nhtml_cosp*nscol_cosp) = R_UNDEF ! +cosp2 emis11_out(1:pcols,1:nhtml_cosp*nscol_cosp) = R_UNDEF ! +cosp2 asym34_out(1:pcols,1:nhtml_cosp*nscol_cosp) = R_UNDEF ! +cosp2 @@ -2280,6 +2326,12 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn where(cam_sunlit(1:ncol) .eq. 0) cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure(1:ncol,i,k) = R_UNDEF end where + where(cam_sunlit(1:ncol) .eq. 0) + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(1:ncol,i,k) = R_UNDEF + end where + where(cam_sunlit(1:ncol) .eq. 0) + cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(1:ncol,i,k) = R_UNDEF + end where enddo do k=1,numMODISReffIceBins where(cam_sunlit(1:ncol) .eq. 0) @@ -2291,6 +2343,20 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn cospOUT%modis_Optical_Thickness_vs_ReffLIQ(1:ncol,i,k) = R_UNDEF end where enddo + enddo !loop i + do i=1,numMODISIWPBins + do k=1,numMODISReffIceBins + where(cam_sunlit(1:ncol) .eq. 0) + cospOUT%modis_IWP_vs_ReffICE(1:ncol,i,k) = R_UNDEF + end where + end do + enddo + do i=1,numMODISLWPBins + do k=1,numMODISReffLiqBins + where(cam_sunlit(1:ncol) .eq. 0) + cospOUT%modis_LWP_vs_ReffLIQ(1:ncol,i,k) = R_UNDEF + end where + end do enddo end if end if @@ -2424,8 +2490,12 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn lwpmodis(1:ncol) = cospOUT%modis_Liquid_Water_Path_Mean iwpmodis(1:ncol) = cospOUT%modis_Ice_Water_Path_Mean clmodis(1:ncol,1:ntau_cosp_modis,1:nprs_cosp) = cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure + clliqmodis(1:ncol,1:ntau_cosp_modis,1:nprs_cosp) = cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq + clicemodis(1:ncol,1:ntau_cosp_modis,1:nprs_cosp) = cospOUT%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice clrimodis(1:ncol,1:ntau_cosp_modis,1:numMODISReffIceBins) = cospOUT%modis_Optical_Thickness_vs_ReffICE clrlmodis(1:ncol,1:ntau_cosp_modis,1:numMODISReffLiqBins) = cospOUT%modis_Optical_Thickness_vs_ReffLIQ + iwprimodis(1:ncol,1:numMODISIWPBins,1:numMODISReffIceBins) = cospOUT%modis_IWP_vs_ReffICE + lwprlmodis(1:ncol,1:numMODISLWPBins,1:numMODISReffLiqBins) = cospOUT%modis_LWP_vs_ReffLIQ endif ! Use high-dimensional output to populate CAM collapsed output variables @@ -2484,6 +2554,20 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn clmodis_cam(i,ipt) = clmodis(i,it,ip) end do end do + ! CAM clliqmodis + do ip=1,nprs_cosp + do it=1,ntau_cosp_modis + ipt=(ip-1)*ntau_cosp_modis+it + clliqmodis_cam(i,ipt) = clliqmodis(i,it,ip) + end do + end do + ! CAM clicemodis + do ip=1,nprs_cosp + do it=1,ntau_cosp_modis + ipt=(ip-1)*ntau_cosp_modis+it + clicemodis_cam(i,ipt) = clicemodis(i,it,ip) + end do + end do ! CAM clrimodis do ip=1,numMODISReffIceBins do it=1,ntau_cosp_modis @@ -2498,6 +2582,20 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn clrlmodis_cam(i,ipt) = clrlmodis(i,it,ip) end do end do + ! CAM iwprimodis + do ip=1,numMODISReffIceBins + do it=1,numMODISIWPBins + ipt=(ip-1)*numMODISIWPBins+it + iwprimodis_cam(i,ipt) = iwprimodis(i,it,ip) + end do + end do + ! CAM lwprlmodis + do ip=1,numMODISReffLiqBins + do it=1,numMODISLWPBins + ipt=(ip-1)*numMODISLWPBins+it + lwprlmodis_cam(i,ipt) = lwprlmodis(i,it,ip) + end do + end do endif ! Subcolums @@ -2824,8 +2922,12 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn call outfld('IWPMODIS',iwpmodis ,pcols,lchnk) call outfld('CLMODIS',clmodis_cam ,pcols,lchnk) + call outfld('CLLIQMODIS',clliqmodis_cam ,pcols,lchnk) + call outfld('CLICEMODIS',clicemodis_cam ,pcols,lchnk) call outfld('CLRIMODIS',clrimodis_cam ,pcols,lchnk) call outfld('CLRLMODIS',clrlmodis_cam ,pcols,lchnk) + call outfld('IWPRIMODIS',iwprimodis_cam ,pcols,lchnk) + call outfld('LWPRLMODIS',lwprlmodis_cam ,pcols,lchnk) end if ! SUB-COLUMN OUTPUT @@ -3456,8 +3558,12 @@ subroutine construct_cosp_outputs(Npoints,Ncolumns,Nlevels,Nlvgrid,Nchan,x) allocate(x%modis_Liquid_Water_Path_Mean(Npoints)) allocate(x%modis_Ice_Water_Path_Mean(Npoints)) allocate(x%modis_Optical_Thickness_vs_Cloud_Top_Pressure(nPoints,numModisTauBins,numMODISPresBins)) + allocate(x%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq(nPoints,numModisTauBins,numMODISPresBins)) + allocate(x%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice(nPoints,numModisTauBins,numMODISPresBins)) allocate(x%modis_Optical_thickness_vs_ReffLIQ(nPoints,numMODISTauBins,numMODISReffLiqBins)) allocate(x%modis_Optical_Thickness_vs_ReffICE(nPoints,numMODISTauBins,numMODISReffIceBins)) + allocate(x%modis_LWP_vs_ReffLIQ(nPoints,numMODISLWPBins,numMODISReffLiqBins)) + allocate(x%modis_IWP_vs_ReffICE(nPoints,numMODISIWPBins,numMODISReffIceBins)) endif ! CALIPSO simulator @@ -3778,6 +3884,14 @@ subroutine destroy_cosp_outputs(y) deallocate(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure) nullify(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure) endif + if (associated(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq)) then + deallocate(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq) + nullify(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Liq) + endif + if (associated(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice)) then + deallocate(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice) + nullify(y%modis_Optical_Thickness_vs_Cloud_Top_Pressure_Ice) + endif if (associated(y%modis_Optical_thickness_vs_ReffLIQ)) then deallocate(y%modis_Optical_thickness_vs_ReffLIQ) nullify(y%modis_Optical_thickness_vs_ReffLIQ) @@ -3786,6 +3900,14 @@ subroutine destroy_cosp_outputs(y) deallocate(y%modis_Optical_thickness_vs_ReffICE) nullify(y%modis_Optical_thickness_vs_ReffICE) endif + if (associated(y%modis_LWP_vs_ReffLIQ)) then + deallocate(y%modis_LWP_vs_ReffLIQ) + nullify(y%modis_LWP_vs_ReffLIQ) + endif + if (associated(y%modis_IWP_vs_ReffICE)) then + deallocate(y%modis_IWP_vs_ReffICE) + nullify(y%modis_IWP_vs_ReffICE) + endif if (associated(y%calipso_cldtype)) then deallocate(y%calipso_cldtype) nullify(y%calipso_cldtype) From 61089977f41664bbe7352db9c51daaa499725c55 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Fri, 10 May 2024 11:01:28 -0500 Subject: [PATCH 162/388] Upate Greenland 20 km SMS and ERS tests. Remove 'exclude_testing' attribute for MALI to allow MALI generation and comparison of MALI hist files for SMS test. Add nl specs for SMS and ERS tests so that hist.am files are NOT written out as part of testing (allows hist files to be compared rather than hist.am files). --- cime_config/config_archive.xml | 2 +- .../testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali | 1 + .../testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali diff --git a/cime_config/config_archive.xml b/cime_config/config_archive.xml index 84de6e0f171..f343fce81ba 100644 --- a/cime_config/config_archive.xml +++ b/cime_config/config_archive.xml @@ -117,7 +117,7 @@ - + rst hist unset diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali new file mode 100644 index 00000000000..8b88e2add6c --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali @@ -0,0 +1 @@ +config_am_globalstats_enable = .false. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali new file mode 100644 index 00000000000..8b88e2add6c --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali @@ -0,0 +1 @@ +config_am_globalstats_enable = .false. From e3f20af2248cb8ac5b701d6b08d4ee84ed987894 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Fri, 10 May 2024 18:22:14 -0500 Subject: [PATCH 163/388] Add default layout for BG case w/ GIS 20km Added defulat PE layout for BG case using GIS 20km for Chrys and PM-cpu. Added some additional explicit stub GLC specs to various new PE layouts (so that these aren't accidentally 'found' and chosen for other layouts w/ an active GLC). --- cime_config/allactive/config_pesall.xml | 58 ++++++++++++++++++++----- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 0db40bd5798..6cf09bf6dc0 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -1490,7 +1490,7 @@ - + --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 4 nodes pure-MPI, ~1.5 sypd -4 @@ -1501,7 +1501,7 @@ -4 - + --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 20 nodes pure-MPI, ~7.25 sypd 1024 @@ -1520,7 +1520,7 @@ 640 - + --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 54 nodes pure-MPI, ~17.5 sypd 2752 @@ -1539,7 +1539,7 @@ 2048 - + --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 105 nodes pure-MPI, ~27.7 sypd 5440 @@ -1560,7 +1560,7 @@ - + gcp12 --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 4 nodes -4 @@ -1573,7 +1573,7 @@ - + pm-cpu --compset WCYCL* --res ne30pg2_r05_IcoswISC30E3r5 on 4 nodes -4 @@ -1588,7 +1588,7 @@ - + --compset WCYCL* --res ne30pg2_r05_IcosXISC30E3r7 on 20 nodes pure-MPI, ~7.25 sypd 1024 @@ -1607,7 +1607,7 @@ 640 - + --compset WCYCL* --res ne30pg2_r05_IcosXISC30E3r7 on 54 nodes pure-MPI, ~17.5 sypd 2752 @@ -1626,7 +1626,7 @@ 2048 - + --compset WCYCL* --res ne30pg2_r05_IcosXISC30E3r7 on 105 nodes pure-MPI, ~27.7 sypd 5440 @@ -2319,7 +2319,7 @@ - + --compset WCYCL* --res ne30pg2_EC30to60E2r2_wQU225EC30to60E2r2 on 48 nodes pure-MPI, ~8.8 sypd 1350 @@ -2663,4 +2663,42 @@ + + + + GIS 20km (low-res) testing config + 128 + 128 + + 512 + 512 + 512 + 512 + 512 + 256 + 512 + 512 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + From 0fd52f61db69a6516a171ff7f2d99931c7d88396 Mon Sep 17 00:00:00 2001 From: dqwu Date: Tue, 14 May 2024 10:34:51 -0500 Subject: [PATCH 164/388] Update modules for intel/gnu,impi/mvapich on Bebop Update modules for intel/gnu,impi/mvapich on Bebop to get system software more update-to-date. --- cime_config/machines/config_machines.xml | 49 +++++++++++++++--------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index f1390183089..4381de43234 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -2854,34 +2854,45 @@ anaconda3/5.2.0 - intel/18.0.4-443hhug - intel-mkl/2018.4.274-jwaeshj - hdf5/1.10.5-3mk3uik - netcdf/4.7.0-krelxcz - netcdf-fortran/4.4.5-74lj75q + gcc/7.4.0 + intel/20.0.4-lednsve + intel-mkl/2020.4.304-voqlapk - intel-mpi/2018.4.274-4hmwfl6 - parallel-netcdf/1.11.0-acswzws + intel-mpi/2019.9.304-i42whlw + hdf5/1.10.7-ugvomvt + netcdf-c/4.4.1-blyisdg + netcdf-cxx/4.2-gkqc6fq + netcdf-fortran/4.4.4-eanrh5t + parallel-netcdf/1.11.0-y3nmmej - mvapich2/2.3.1-verbs-omjz3ck - parallel-netcdf/1.11.2-7fy6qz3 + mvapich2/2.3.6-verbs-x4iz7lq + hdf5/1.10.7-igh6foh + netcdf-c/4.4.1-gei7x7w + netcdf-cxx/4.2-db2f5or + netcdf-fortran/4.4.4-b4ldb3a + parallel-netcdf/1.11.0-kj4jsvt - gcc/8.2.0-g7hppkz - intel-mkl/2018.4.274-2amycpi - hdf5/1.8.16-mz7lmxh - netcdf/4.4.1-xkjcghm - netcdf-fortran/4.4.4-mpstomu + gcc/8.2.0-xhxgy33 + intel-mkl/2020.4.304-d6zw4xa - intel-mpi/2018.4.274-ozfo327 - parallel-netcdf/1.11.0-filvnis + intel-mpi/2019.9.304-rxpzd6p + hdf5/1.10.7-oy6d2nm + netcdf-c/4.4.1-fysjgfx + netcdf-cxx/4.2-oaiw2v6 + netcdf-fortran/4.4.4-kxgkaop + parallel-netcdf/1.11.0-fce7akl - mvapich2/2.3-bebop-3xi4hiu - parallel-netcdf/1.11.2-hfn33fd + mvapich2/2.3-bebop-a66r4jf + hdf5/1.10.5-ejeshwh + netcdf/4.4.1-ve2zfkw + netcdf-cxx/4.2-2rkopdl + netcdf-fortran/4.4.4-thtylny + parallel-netcdf/1.11.0-kozyofv $CIME_OUTPUT_ROOT/$CASE/run @@ -2896,7 +2907,7 @@ $SHELL{dirname $(dirname $(which pnetcdf_version))} - + $SHELL{which h5dump | xargs dirname | xargs dirname} From a67b671da02a2e1af239fc06dbd86dae5ed0cfbd Mon Sep 17 00:00:00 2001 From: Alice Barthel Date: Tue, 14 May 2024 14:41:21 -0700 Subject: [PATCH 165/388] added under_sea_ice restoring for G-cases by default --- components/mpas-ocean/bld/build-namelist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-ocean/bld/build-namelist b/components/mpas-ocean/bld/build-namelist index c8e1c1e3a7a..d4af8f86d99 100755 --- a/components/mpas-ocean/bld/build-namelist +++ b/components/mpas-ocean/bld/build-namelist @@ -1024,7 +1024,7 @@ if ($OCN_FORCING eq 'datm_forced_restoring') { add_default($nl, 'config_use_surface_salinity_monthly_restoring', 'val'=>".true."); add_default($nl, 'config_salinity_restoring_constant_piston_velocity', 'val'=>"1.585e-6"); add_default($nl, 'config_salinity_restoring_max_difference', 'val'=>"100."); - add_default($nl, 'config_salinity_restoring_under_sea_ice', 'val'=>".false."); + add_default($nl, 'config_salinity_restoring_under_sea_ice', 'val'=>".true."); } else { add_default($nl, 'config_use_activeTracers_surface_restoring'); add_default($nl, 'config_use_surface_salinity_monthly_restoring'); From 6480da5b493b94a12bab67418f8478597e108cc1 Mon Sep 17 00:00:00 2001 From: Alice Barthel Date: Tue, 14 May 2024 14:56:18 -0700 Subject: [PATCH 166/388] modified sss restoring to dt by default --- .../mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml | 2 +- .../mpas-ocean/src/tracer_groups/Registry_activeTracers.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml index 248654ef10f..98c5b18ce17 100644 --- a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml +++ b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml @@ -660,7 +660,7 @@ .false. .false. .false. -'0000-00-01_00:00:00' +'dt' 1.585e-6 0.5 .false. diff --git a/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml b/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml index 3b534439148..a4c032bb478 100644 --- a/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml +++ b/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml @@ -31,9 +31,9 @@ description="If true, apply monthly salinity restoring using a uniform piston velocity, defined at run-time by config_salinity_restoring_constant_piston_velocity. When false, salinity piston velocity is specified in the input file by salinityPistonVelocity, which may be spatially variable." possible_values=".true. or .false." /> - Date: Tue, 14 May 2024 15:34:41 -0700 Subject: [PATCH 167/388] modified for under sea ice restoring to be default in all cases --- .../bld/namelist_files/namelist_defaults_mpaso.xml | 2 +- .../src/shared/mpas_ocn_tracer_surface_restoring.F | 10 ++++++---- .../src/tracer_groups/Registry_activeTracers.xml | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml index 98c5b18ce17..4590e8c3c8a 100644 --- a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml +++ b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml @@ -663,7 +663,7 @@ 'dt' 1.585e-6 0.5 -.false. +.true. .false. diff --git a/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F b/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F index f47608ef0d9..cc014b3f236 100644 --- a/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F +++ b/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F @@ -344,7 +344,8 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & if (config_salinity_restoring_under_sea_ice) then - ! Simulation has landIceMask AND config_salinity_restoring_under_sea_ice=.true. + ! Simulation has landIceMask AND + ! config_salinity_restoring_under_sea_ice=.true. (default) do iCell = 1, nCells if (landIceMask(iCell)==1) then ! Turn off salinity restoring in this cell @@ -362,7 +363,7 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & else ! config_salinity_restoring_under_sea_ice = .false. - ! Simulation has landIceMask AND config_salinity_restoring_under_sea_ice=.false. (default) + ! Simulation has landIceMask AND config_salinity_restoring_under_sea_ice=.false. do iCell = 1, nCells if (landIceMask(iCell)==1) then ! Turn off salinity restoring in this cell @@ -386,7 +387,8 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & if (config_salinity_restoring_under_sea_ice) then - ! Simulation has NO landIceMask AND config_salinity_restoring_under_sea_ice=.true. + ! Simulation has NO landIceMask AND + ! config_salinity_restoring_under_sea_ice=.true. (default) do iCell = 1, nCells deltaS = surfaceSalinityMonthlyClimatologyValue(iCell) - activeTracers(indexSalinity,1,iCell) if (deltaS > config_salinity_restoring_max_difference) deltaS = config_salinity_restoring_max_difference @@ -398,7 +400,7 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & else ! config_salinity_restoring_under_sea_ice = .false. - ! Simulation has NO landIceMask AND config_salinity_restoring_under_sea_ice=.false. (default) + ! Simulation has NO landIceMask AND config_salinity_restoring_under_sea_ice=.false. do iCell = 1, nCells deltaS = surfaceSalinityMonthlyClimatologyValue(iCell) - activeTracers(indexSalinity,1,iCell) if (deltaS > config_salinity_restoring_max_difference) deltaS = config_salinity_restoring_max_difference diff --git a/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml b/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml index a4c032bb478..916df21b70c 100644 --- a/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml +++ b/components/mpas-ocean/src/tracer_groups/Registry_activeTracers.xml @@ -43,8 +43,8 @@ description="Maximum allowable difference between surface salinity and climatology, in grams salt per kilogram seawater." possible_values="any non-negative number" /> - From 8d3ffda6fa939fd12c3dc3dbe6b080aa4402a415 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 14 May 2024 17:07:31 -0600 Subject: [PATCH 168/388] add pages for new grid support guide --- .../adding-grid-support-SE-grid-overview.md | 23 ++ .../adding-grid-support-grid-types.md | 13 + .../adding-grid-support-step-by-step-guide.md | 26 ++ .../RRM_grid_reference.png | Bin 0 -> 171634 bytes .../add-grid-config.md | 1 + .../generate-RRM-grid-file.md | 256 ++++++++++++++++++ .../generate-atm-initial-condition.md | 1 + .../generate-dry-deposition.md | 1 + .../generate-lnd-initial-condition.md | 1 + .../generate-lnd-input-data.md | 1 + .../generate-mapping-files.md | 7 + .../generate-new-grid-file.md | 36 +++ .../generate-topo-file.md | 1 + .../grid_illustration_ne4np4.png | Bin 0 -> 84626 bytes .../grid_illustration_ne4pg2.png | Bin 0 -> 108214 bytes docs/dev-guide/adding-grid-support/index.md | 8 + docs/development.md | 1 + 17 files changed, 376 insertions(+) create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/RRM_grid_reference.png create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/add-grid-config.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-RRM-grid-file.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-atm-initial-condition.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-dry-deposition.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-initial-condition.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-input-data.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-mapping-files.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-new-grid-file.md create mode 100644 docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md create mode 100644 docs/dev-guide/adding-grid-support/grid_illustration_ne4np4.png create mode 100644 docs/dev-guide/adding-grid-support/grid_illustration_ne4pg2.png create mode 100644 docs/dev-guide/adding-grid-support/index.md diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md b/docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md new file mode 100644 index 00000000000..29f2e895430 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md @@ -0,0 +1,23 @@ +# Atmosphere Grid Overview + +The E3SM atmosphere component uses a cube-sphere grid, partly to avoid the convergence of latitude lines at the poles. The grid is constructed by subdividing each cube face into NxN elements and then projecting these to a spherical geometry. + +## The np4 GLL Grid + +The atmospheric dycore is based on the spectral element (SE) method using the Gauss-Lobatto-Legendre (GLL) quadrature aproach. An irregular grid of 4x4 GLL nodes (i.e. np4) is used to represent the model state within each element of the cube-sphere grid. The illustration below indicates the GLL nodes of the ne4np4 grid with green dots, while the elements are outlined in blue. Notice the irregular spacing of the GLL nodes, which causes them to cluster at the element corners. + +While the atmosphere history output is primarily on the physics grid (see below), it is possible to output on the np4 grid. The input topography and initial condition data must be on the np4 grid. When mapping between SE and FV grids TempestRemap should be used. SE GLL data does not naturally represent as FV type cell averages, and thus mapping tools which only work with cell centered data (ESMF, SCRIP) should be avoided. + +For a np4 grid with N elements per cube edge the total number of unique GLL nodes can be calculated as: +`N*(np-1)^2 + 2` + +![ne4np4 grid illustration](grid_illustration_ne4np4.png) + +## The pg2 "physgrid" + +Starting in v2, physics calculations and history output in E3SM use a quasi-equal area finite volume (FV) grid, rather the GLL nodes of the spectral element grid. This FV grid is constructed byt dividing each spectral element of the cube-sphere into a grid of 2x2 subcells, referred to as "pg2" or "physgrid" (shown below). Finer divisions of the spectral element are possible, such as 3x3, but these grids do not seem to have any notable advantages (see [Hannah et al. 2021](https://agupubs.onlinelibrary.wiley.com/doi/full/10.1029/2020MS002419)). Quantities on the physgrid should be considered cell average values over each FV cell, rather than nodal values. + +For a pg2 grid with N elements per cube edge the total number of physics columns can be calculated as: +`ncol = N*N*6*(2*2)` + +![ne4pg2 grid illustration](grid_illustration_ne4pg2.png) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md b/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md new file mode 100644 index 00000000000..036312a4663 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md @@ -0,0 +1,13 @@ +# Types of Grid Description Files + +- **Exodus file**: ex. "ne4.g". This is a netcdf file following Exodus conventions. It gives the corner locations of all elements on the sphere and their connectivity. It is independent of the polynomial order used inside the element ("np"). This file is used by TempestRemap (TR) to generate mapping files. The polynomial order is a command line option and the GLL nodes are internally generated by TR. + +- **SCRIP file**: ex. "ne4pg2.scrip.nc". This file contains a description of the atmosphere physics grid in the format used by the original incremental remap tool SCRIP. It is used for most output and also used to generate mapping files between components and for post-processing of most output. + +Less common “GLL” metadata files needed for specialized purposes: + +- **"dual grid" SCRIP file**: ex. "ne4np4_scrip.nc". This file contains a SCRIP format description of the GLL grid. It includes the locations of the GLL nodes and artificial bounding polygons around those nodes. Ideally the spherical area of each polygon will match the GLL weight ("exact GLL areas"), but not all tools can achieve exact areas. Inexact areas does not impact the accuracy of the resulting mapping algorithm, it just means that mass will not be exactly conserved by the mapping algorithm. These files are often problematic to generate, so it is advised to avoid using workflows that require this. This was previously needed in E3SMv2 configurations by the cube_to_target topography dataset generation tool, but effort has been made to eliminate this requirement. It was also historically used in E3SMv1 to create ocean/atm mapping files (exact GLL areas was important here to conserve fluxes). + +- **"latlon" file**: ex. "ne4np4_latlon.nc". This file contains a list of all the GLL nodes in the mesh (in latitude/longitude coordinates). The list of GLL nodes must be in the the internal HOMME global id ordering, matching the ordering used in EAM GLL grid output. It also contains the connectivity of the GLL subcell grid. This file is no longer needed for any E3SM workflow. + +- **"pentagons" file**: ex. "ne30np4_pentagons.nc". These files represent a mostly outdated approach of dealing with data on the np4 grid. While the np4 grid provides a spectral element representation of data with weights on GLL nodes, the term "dual grid" refers to a finite volume approximation of the same data by constructing polygons around each GLL node such that the cell area matches the weight of each node. The word "pentagons" was used because that is the most number of sides used by the polygons. These files are increasingly difficult to generate as the global resolution becomes finer because the polygon construction is a costly iterative process. Some tools to generate these files were either the NCL code `HOMME2SCRIP.ncl` or the matlab code `dualgridgenerate.m`. These types of files are no longer needed for any E3SM workflow, although some of these files can still be found in the E3SM data repository. \ No newline at end of file diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide.md new file mode 100644 index 00000000000..48aa14b9720 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide.md @@ -0,0 +1,26 @@ +# Adding Support for New Grids + +The purpose of this guide is to outline all the necessary steps for running E3SM on a new grid for the atmosphere and land components. The process is similar for uniform and regionally refined grids, although regionally refined cases will likely require some special considerations which will be noted where appropriate. + +If you wish to add a new ocean and sea-ice mesh you will need to use the compass tool to generate the mesh and dynamically adjusted initial condition. This procedure is detailed in a separate tutorial: + + + + + + +## Step-by-Step Guide + +1. [Generate a new grid file ](adding-grid-support-step-by-step-guide/generate-new-grid-file.md) +1. [Generate mapping files ](adding-grid-support-step-by-step-guide/generate-mapping-files.md) +1. [Generate domain files ](/generate_domain_files/) +1. [Generate a topography file ](adding-grid-support-step-by-step-guide/generate-topo-file.md) +1. [Generate atmospheric initial condition ](adding-grid-support-step-by-step-guide/generate-atm-initial-condition.md) +1. [Generate land input data (*fsurdat*) ](adding-grid-support-step-by-step-guide/generate-lnd-input-data.md) +1. [Generate land initial condition (*finidat*) ](adding-grid-support-step-by-step-guide/generate-lnd-initial-condition.md) +1. [Generate a dry deposition file (*depends on use case*) ](adding-grid-support-step-by-step-guide/generate-dry-deposition.md) +1. [Add new grid configuration to E3SM ](adding-grid-support-step-by-step-guide/add-grid-config.md) + +## Other Useful Tutorials + +1. [Generate a RRM Grid File with SQuadGen ](adding-grid-support-step-by-step-guide/generate-RRM-grid-file.md) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/RRM_grid_reference.png b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/RRM_grid_reference.png new file mode 100644 index 0000000000000000000000000000000000000000..d83e9262cfd2f8a4634648954f52c747df7964b2 GIT binary patch literal 171634 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
Z;RTk}xcc(%4`OpB55H{N_@#TM|XE1C1 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
Oxk5cE*j`?P6q8HZ-@ z8qfWia0~jLw0nX;wa5W?0mQe;CB@3zvap@I$9_}6#WQ!i|3E)Lz<^TftQBn1ZnXZHdVvC@h9duwxY8HavqCiuPaSGN5__-xc zi7U!9X)dJq!M?2dnbnueI8OHB3A+T$%x5lq&4al^(aMEk3t5%&jq@Q{0-HOPyFCvafyfnrJliCawds|z<6VW0kLtwMwtK}}ZPI>2$vlS4mi?!x zJulA^+>^llS-7ht3WCHDfrrblT%L~VYteMGl-b@?Jo7Yv4%DfswX28vb59yH%fI10lbM@P1gh^Ta12t62>RU?r?uYqVf4ss}omypOj0BAr66GrJ7A4bg>icoc*V1GSrrG8&QKS4|Qv=MHG zG*{38D#3eAP?rx|7bw_Jek}Z7?$2>$m>nlpyIg9z40^Y!NtQ87YO9U zeUQ~^iN0?;wW8+$jQxNQ1DJ2SrjYC5IB^~&2I@wi`zHYilw68_faqV0Z>^5IQ3ruU z&__$-r3CB+{Ad5t@OZcG7!PT+qw0|?%P>1526v@)h?`e_Ys%Rm!4?l%GnvoHQU>6z zp~0AP*bpvMX7>&`Q5;7`Spl$(RV=57Ky8$ai;hFy&7oyFZAoJiHrfn&CL93VxQcn8 zRvjP$;yv>uJQggc$7150FbR}hQoCK+9#t|UjnUdTm`cZD3q#^CI80vyCzQ}|U4(pt zC;&Ww7J$cqNPrqaezlb2Kyo<%7S@C!qA5^gXHZr}mzOW#z?@GSO~i$Ckk684OWpL= qu|-r}*ASM%F>Oql?V1mgxHLOVvIN6eEpbGiC9VRJTmn>c0001!cB`HM literal 0 HcmV?d00001 diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/add-grid-config.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/add-grid-config.md new file mode 100644 index 00000000000..aae60268aba --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/add-grid-config.md @@ -0,0 +1 @@ +# Add New Grid Configuration to E3SM diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-RRM-grid-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-RRM-grid-file.md new file mode 100644 index 00000000000..502aa766a5a --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-RRM-grid-file.md @@ -0,0 +1,256 @@ +# Generate a RRM Grid File with SQuadGen + + + + +There are three ways to create a regionally refined grid file for E3SM using [SQuadGen](https://github.com/ClimateGlobalChange/squadgen), which are outlined below. + +## Using a PNG Image File + +The most common is to create a grayscale `.png` image file with the correct aspect ratio that defines one or more refinement areas. + +The input PNG is a grayscale representation of a regular latitude-longitude grid (i.e. equiangular projection) with the level of shading determining the level of refinement: white for the coarse grid and black where maximum refinement is desired. Shades of gray can be used to impose intermediate levels of refinement. To determine the refinement region on the cubed-sphere mesh, each volume on the cubed-sphere grid is sampled from the PNG image to determine the desired level of refinement on that grid. The transition region is then built around each refinement region using "paving" tiles, with optional smoothing of edges. + +Once the PNG file is created it can be used to generate the new exodus file. The example below creates a 3x refinement based on the ne30 grid that, which it typically used for production runs. + +```shell +./SQuadGen --refine_file ${GRIDNAME}.png --resolution 30 --refine_level 3 --refine_type LOWCONN --smooth_type SPRING --smooth_dist 3 --smooth_iter 20 --output ${DATA_PATH}/${GRIDNAME}.g +``` + +### Creating the PNG file with an image editor + +It is often useful to start with a background image that already has the correct aspect ratio and is centered on 0 degrees longitude. The following PNG image (with base grid ne16) can be used as a template for drawing your refinement region so that grid lines are parallel to cubed-sphere arcs. This PNG file can be set as a background image in an editor like Photoshop or GIMP. + +![RRM_grid_reference.png](RRM_grid_reference.png) + +The refined region is then drawn on top of this image in a separate layer. You can set the transparency between layers at, i.e. 50% with the grayscale image in front of the template. When you are ready to save the image, you can change the transparency to 0% and export the image as a PNG. + +If a different "base grid" image is desired with more or less detail, this can be generated with: + +```shell +./SQuadGen --resolution --output base_grid.g +``` + +where `ne` is your desired base grid resolution. The grid image can then be plotted with the `gridplot.ncl` script that is included with SQuadGen. Alternatively, [PyNGL](https://www.pyngl.ucar.edu/) is a python replacement for NCL that also has good support for plotting unstructured meshes (despite being in "maintenance mode"). + +### Creating the PNG file with a python script + +The previous method of using an image editor can be somewhat cumbersome and inaccurate. Scripted generation of the refinement region is possible with python. + +In the first example below a SCRIP format grid file is used so that individual elements can be shaded, but this method was intended for the cell shading capability of PyNGL. The SCRIP file used in these examples can be generated with 3 simple TempestRemap commands: + +```shell +NE=30 +GenerateCSMesh --alt --res ${NE} --file ${GRID_FILE_PATH}/ne${NE}.g +GenerateVolumetricMesh --in ${GRID_FILE_PATH}/ne${NE}.g --out ${GRID_FILE_PATH}/ne${NE}pg2.g --np 2 --uniform +ConvertMeshToSCRIP --in ${GRID_FILE_PATH}/ne${NE}pg2.g --out ${GRID_FILE_PATH}/ne${NE}pg2_scrip.nc +``` + +For other plotting libraries it may be preferrable to use an equiangular SCRIP grid file, which can be generated with a simple NCO command. Here is an example of a 1 degree grid: + +```shell +ncremap -G ttl=Equi-Angular grid 1x1 degree, dimensions 180x360, cell edges on Poles/Equator and Prime Meridian/Date Line#latlon=180,360#lat_typ=uni#lon_typ=grn_wst -g /Users/zender/data/grids/cmip6_180x360_scrip.nc +``` + +Below is some example python code to generate a "feathered" refined region around a given central point. The resulting numpy array can then be plotted with your preferred plotting library (ex. matplotlib, pyngl) + +
+ generate_RRM_png_feathered.py + ```python + import os, ngl, numpy as np, xarray as xr + target_lat, target_lon = 39.7392, 360-104.9903 # Denver, CO + #------------------------------------------------------------------------------- + scrip_ds = xr.open_dataset(os.getenv('HOME')+'/E3SM/data_grid/ne30pg2_scrip.nc') + ncol = len(scrip_ds['grid_area']) + deg_to_rad,rad_to_deg = np.pi/180., 180./np.pi + #------------------------------------------------------------------------------- + # method for calculating the length of great circle arcs + def calc_great_circle_distance(lat1,lat2,lon1,lon2): + ''' input should be in degrees ''' + dlon = lon2 - lon1 + cos_dist = np.sin(lat1*deg_to_rad)*np.sin(lat2*deg_to_rad) + \ + np.cos(lat1*deg_to_rad)*np.cos(lat2*deg_to_rad)*np.cos(dlon*deg_to_rad) + # print( str(cos_dist.min()) +" "+ str(cos_dist.max()) ) + cos_dist = np.where(cos_dist> 1.0, 1.0,cos_dist) + cos_dist = np.where(cos_dist<-1.0,-1.0,cos_dist) + dist = np.arccos( cos_dist ) + return dist + #------------------------------------------------------------------------------- + # method for defining a feathered refinement region + def define_refinement( ncol, dmin, dmax, + target_lat, target_lon, + center_lat, center_lon, + refine_level): + # loop through all points and calculate distance to center + # NOTE - distance units are in radians (max value = pi) + for n in range(ncol): + d = calc_great_circle_distance(target_lat, center_lat[n] ,target_lon, center_lon[n]) + if d<=dmin: refine_level[n] = 1 + if d>dmin and d<=dmax: refine_level[n] = ( dmax - d ) / ( dmax - dmin ) + if d>dmax: refine_level[n] = 0 + return refine_level + #------------------------------------------------------------------------------- + # define refinement regions - distance thesholds in radians + min_threshold = 1*deg_to_rad + max_threshold = 10*deg_to_rad + refine_level = np.zeros(ncol) + # define continuous refinement based on distance + define_refinement( ncol, min_threshold, max_threshold, + target_lat, target_lon, + scrip_ds['grid_center_lat'].values, + scrip_ds['grid_center_lon'].values, + refine_level ) + #------------------------------------------------------------------------------- + # create PNG image using PyNGL + wkres = ngl.Resources() + npix = 4096; wkres.wkWidth,wkres.wkHeight=npix,npix + wkres.wkForegroundColor = [1.,1.,1.] + wkres.wkBackgroundColor = [1.,1.,1.] + wks = ngl.open_wks('png',fig_file,wkres) + # Create custom colormap + num_clr = 50 + fill_clr = np.zeros((num_clr,3)) + for n in range(num_clr): fill_clr[n,:] = float(n) / float(num_clr) + # define plot resources + res = ngl.Resources() + res.nglDraw = False + res.nglFrame = False + res.tmXTOn = False + res.tmXBOn = False + res.tmYLOn = False + res.tmYROn = False + res.cnFillOn = True + res.cnLinesOn = False + res.cnLineLabelsOn = False + res.cnInfoLabelOn = False + res.mpGridAndLimbOn = False + res.mpPerimOn = False + res.mpOutlineBoundarySets = 'NoBoundaries' + res.lbLabelBarOn = False + res.cnFillPalette = fill_clr + res.tfPolyDrawOrder = 'PreDraw' + res.sfXArray = scrip_ds['grid_center_lon'].values + res.sfYArray = scrip_ds['grid_center_lat'].values + #------------------------------------------------------------------------------- + # Use Raster fill mode instead of cell fill + res.cnFillMode = 'RasterFill' + plot = ngl.contour_map(wks,refine_level,res) + #------------------------------------------------------------------------------- + # use pre-draw polygon to fill in white areas near poles + #------------------------------------------------------------------------------- + gsres = ngl.Resources() + gsres.gsFillColor = 'black' + gsres.gsEdgesOn = False + py = [ -89.9, 89.9, 89.9,-89.9, -89.9] + px = [ 360. , 360. , 0. , 0. , 360. ] + ngl.polygon(wks, plot, px, py, gsres) + #------------------------------------------------------------------------------- + ngl.draw(plot) + ngl.frame(wks) + ngl.end() + #------------------------------------------------------------------------------- + # crop white space from png file + if os.path.isfile(f'{fig_file}.png') : + cmd = f'convert -trim +repage {fig_file}.png {fig_file}.png' + os.system(cmd) + os.system(cmd) # second call helps remove gray lines at edge + # if npix = 4096: + else: + raise FileNotFoundError(f'\n{fig_file}.png does not exist?!\n') + #------------------------------------------------------------------------------- + # apply gaussian blur + from PIL import Image, ImageFilter + image = Image.open(f'{fig_file}.png') + for n in range(nsmooth): image = image.filter(ImageFilter.GaussianBlur(radius=6)) + image = image.save(f'{fig_file}.png') + #------------------------------------------------------------------------------- + print(); print(f' {fig_file}.png'); print() + #------------------------------------------------------------------------------- + ``` +
+ +The next example creates a refinement region based on land fraction. + +
+ generate_RRM_png_landfrac.py + ```python + import os, ngl, numpy as np, xarray as xr + refine_level = 1 + nsmooth = 4 + land_data_file = 'inputdata/atm/cam/topo/USGS-gtopo30_0.9x1.25_remap_c051027.nc' + ds = xr.open_dataset(land_data_file) + lat = ds['lat'] + lon = ds['lon'] + landfrac = ds['LANDFRAC'] + nlat,nlon = len(lat),len(lon) + #------------------------------------------------------------------------------- + # switch to center data on prime meridian + lon_tmp = np.zeros(nlon) + lon_tmp[:int(nlon/2)] = lon[-int(nlon/2):].values - 360. + lon_tmp[int(nlon/2):] = lon[ :int(nlon/2)].values + lon = xr.DataArray(lon_tmp,dims={'lon':lon}) + landfrac_tmp = np.zeros(landfrac.shape) + landfrac_tmp[:,:int(nlon/2)] = landfrac[:,-int(nlon/2):].values + landfrac_tmp[:,int(nlon/2):] = landfrac[:, :int(nlon/2)].values + landfrac = xr.DataArray(landfrac_tmp,dims={'lat':lat,'lon':lon}) + #------------------------------------------------------------------------------- + # mask out anarctica + for j in range(nlat): + if lat[j]<-60: landfrac[j,:] = 0.0 + #------------------------------------------------------------------------------- + # Apply 2D smoothing to feather edges at coastlines + if nsmooth>0: + for s in range(nsmooth): + tmp = np.copy(landfrac) + for j in range(1,nlat-2): + for i in range(nlon): + im1 = nlon-1 if i==0 else i-1 + ip1 = 0 if i==nlon-1 else i+1 + smooth_y = ( 0.25*tmp[j-1,i ] + 0.5*tmp[j,i] + 0.25*tmp[j+1,i ] ) + smooth_x = ( 0.25*tmp[j ,im1] + 0.5*tmp[j,i] + 0.25*tmp[j ,ip1] ) + smooth_d1 = ( 0.25*tmp[j-1,im1] + 0.5*tmp[j,i] + 0.25*tmp[j+1,ip1] ) + smooth_d2 = ( 0.25*tmp[j-1,ip1] + 0.5*tmp[j,i] + 0.25*tmp[j+1,im1] ) + landfrac[j,i] = ( smooth_y + smooth_x + smooth_d1 + smooth_d2 ) / 4. + for j in range(nlat): + for i in range(nlon): + if landfrac[j,i]<0.8: landfrac[j,i] = 0.0 + #------------------------------------------------------------------------------- + # Generate image of refined region using MPL + fig = plt.figure(figsize=(36/4,18/4)) + ax = fig.add_subplot(1,1,1) + cs = ax.contourf(lon, lat, landfrac, levels=[0.0,0.5,1.0],colors=['#000000','#FFFFFF','#FFFFFF']) + ax.xaxis.set_major_locator(plt.NullLocator()) + ax.yaxis.set_major_locator(plt.NullLocator()) + fig.tight_layout() + plt.axis('off') + plt.savefig(refine_png_file,pad_inches=0,bbox_inches='tight') + print(f'\nrefine_png_file: {refine_png_file}\n') + #------------------------------------------------------------------------------- + # more smoothing via gaussian blur from the pillow package + from PIL import Image, ImageFilter + image = Image.open(f'{refine_png_file}') + for n in range(nsmooth): image = image.filter(ImageFilter.GaussianBlur(radius=3)) + image = image.save(f'{refine_png_file}') + #------------------------------------------------------------------------------- + ``` +
+ +## Using a Refinement Map + +If `--loadcsrefinementmap` is specified the refinement map will be reloaded from a previously generated refine_map.dat file. This option allows for manual editing of the cubed-sphere refine map. + +## Using Rectangular Patches + +SQuadGen can now be used with the `--refine_rect` argument to define rectangular patches on the fly without the need for an image file. This argument takes the latitude and longitude corner locations that define the quadralateral, as well as the desirec refinement level: + +```shell +--refine_rect ",,,," +``` + +## A Note on testing RRM Quality + +RRM "quality" can be measured with the “Max Dinv-based element distortion” metric. This will be printed in the log file for standalone HOMME or EAM simulations and can be obtained from the log files during the topography generation process. + +This metric measures how distorted the elements become in the mesh transition region. It is the ratio of the two singular values of the 2x2 derivative matrix of the element map to the unit square, representing the ration of the largest length scale to the smallest length scale. + +A grid of perfect quadrilaterals will have a value of 1.0. The equal-angle cubed-sphere grid has a value of 1.7. A high quality regionally refined grid will have a value less than 4. With a high quality grid, usually one can run with the timesteps used in a uniform grid with matching fine resolution. RRM grids with a value > 4 may require smaller timesteps for stability. Very large values indicate a problem with the grid and it should be redesigned. diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-atm-initial-condition.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-atm-initial-condition.md new file mode 100644 index 00000000000..6f77f7b5ed2 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-atm-initial-condition.md @@ -0,0 +1 @@ +# Generate Atmospheric Initial Condition diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-dry-deposition.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-dry-deposition.md new file mode 100644 index 00000000000..37373e80c0b --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-dry-deposition.md @@ -0,0 +1 @@ +# Generate a Dry Deposition File diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-initial-condition.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-initial-condition.md new file mode 100644 index 00000000000..63445028dff --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-initial-condition.md @@ -0,0 +1 @@ +# Generate Land Initial Condition (*finidat*) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-input-data.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-input-data.md new file mode 100644 index 00000000000..c36b13bcb4a --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-lnd-input-data.md @@ -0,0 +1 @@ +# Generate Land Input Data (*fsurdat*) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-mapping-files.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-mapping-files.md new file mode 100644 index 00000000000..ea9906577ad --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-mapping-files.md @@ -0,0 +1,7 @@ +# Generate mapping files + +In order to pass data between different components at runtime, a set of mapping files between each component is generated offline. + +See [Recommended Mapping Procedures for E3SM Atmosphere Grids](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/178848194/Recommended+Mapping+Procedures+for+E3SM+Atmosphere+Grids) for a discussion of different remap algorithms and when to use each. + +TempestRemap and ESMF are the backends that generate the mapping weights, but this is all nicely encapsulated using ncremap. Tempest is the preferred method for creating mapping files. ncremap will call TempestRemap or ESMF depending on the algorithm argument and input file types. If exodus files are provided (i.e. `*.g`) then TempestRemap commands will be used. The ESMF tools are adequate for making atmosphere-only-type component sets for E3SM, but this tool is less conservative than TempestRemap. If you are making grids for a coupled run, then TempestRemap should be used wherever possible. Currently, TempestRemap has trouble with masked grids, such those that are needed for land data generation, so ESMF is still required for certain tasks. diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-new-grid-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-new-grid-file.md new file mode 100644 index 00000000000..b2faa43fe29 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-new-grid-file.md @@ -0,0 +1,36 @@ +# Generate a new Grid File + +In order to generate mapping files between a new atmosphere grid and the surface component grids, we need a file that describes the new grid. [TempestRemap](https://github.com/ClimateGlobalChange/tempestremap) is our preferred tool for grid file generation because it can handle the spectral element grids used by the atmosphere dycore. The initial grid file will be saved in an "exodus" file with a `.g` extension (see [Types of Grid Description Files](../adding-grid-support-grid-types.md) for more info). TempestRemap can be installed via conda. + +## Generating a Standard Exodus Grid File + +Once TempestRemap is in our environment we can easily generate an exodus file by calling TempestRemap directly: + +```shell +GenerateCSMesh --alt --res 4 --file ne4.g +``` + +## Generating a Regionally Refined Grid File + +For a regionally refined mesh (RRM) [SQuadGen](https://github.com/ClimateGlobalChange/squadgen) is used to define the refined area(s). [This tutorial](generate-RRM-grid-file.md) includes details and examples of using SQuadGen to generate RRM grid files. + +The naming convention for RRM grid files should follow: + +```shell +_x.g +``` + +For example, for a RRM with 4x refinement from ne30 to ne120 over CONUS, we should use the convention conus_ne30x4.g (note that existing meshes may have used the old naming convention `xv.g`, but future meshes should use the new naming convention). + +The Exodus file contains only information about the position of the spectral element on the sphere. For SE aware utilities such as TempestRemap, they can use the polynomial order and the reference element map to fill in necessary data such as the locations of the nodal GLL points. For non-SE aware utilities, we need additional meta data, described in the next section. + +## Generating a "pg2" SCRIP Grid File + +Starting in E3SMv2 the physics calculations and standard history output use a finite volume (FV) "pg2" grid. Online mapping within the component coupler between the atmosphere and surface components requires FV-to-FV type maps, and generating these maps will require a grid file for pg2 grid. These are easily generated with TempestRemap commands as follows: + +```shell +NE=30 +GenerateCSMesh --alt --res ${NE} --file ${GRID_FILE_PATH}/ne${NE}.g +GenerateVolumetricMesh --in ${GRID_FILE_PATH}/ne${NE}.g --out ${GRID_FILE_PATH}/ne${NE}pg2.g --np 2 --uniform +ConvertMeshToSCRIP --in ${GRID_FILE_PATH}/ne${NE}pg2.g --out ${GRID_FILE_PATH}/ne${NE}pg2_scrip.nc +``` diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md new file mode 100644 index 00000000000..47ba4345d0b --- /dev/null +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -0,0 +1 @@ +# Generate a Topography File diff --git a/docs/dev-guide/adding-grid-support/grid_illustration_ne4np4.png b/docs/dev-guide/adding-grid-support/grid_illustration_ne4np4.png new file mode 100644 index 0000000000000000000000000000000000000000..49f71cf29c045969748534745a24bb0f3ba774bb GIT binary patch literal 84626 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%0DXlv*7tZ+?B+2^pzEFi!EtE(EBj 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

VSKeyz-M?U$P5(6w9NN2e;)|Ffe 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 z zqO|%w$vG}fX0D&l&>@m&VB8S7K*X(Pnr92hBLs3cdUwOW5-VQ=H~rm6A4<5Plts5G zTjM)J0SQ_qVQeJ2VFCWaLWY#7997EnSkG19enYQqjOrROCVGl<^@&wU0)!|ZyzdQ83m zP}z0?ya*Vb7<&gmM(gK<(Mv@f*tc=l#ZyB|P?{qx zi@#CS&b$KHv?y9W1|K{)WWYfh@&4VIp-X#3umS1MpLcUsOS|kOreKjImBDNfVG-h-Yhd7Pt~o z2e_ob9O_y|05MpbQkv5D>BQEdHpiHV7iF)RfK8Xn{gD^+-U5b3qeEx3M)vZmRX@SP z>S<$N_%^Pw!tb>Wdzp1O4?bl--fEo3JJsDwvt3=pKH?6(e@QAguGX-1WwwoqgJ|cy zKaza(B0Yc3$cG|Sd@71FNQL8ywz&7rSs}6W^bh|k3Wj+lWJ&?jui8I9!xO!=2!XK} zEY3q>6A`!)>aw}Ik8pSNg{%Rk$;+Z0)9pFi3bG^#Eo$(qMyQlUX_eZCEU&_?sN2L} z`qbcRG&6xa$q4cEUSW`X4>9JR={TuXZ$+sMybu(&^z&gu?CF=JuH?5cGj&UY$0+J! zS_}zH`&p*v-wjsg3e|NQ8t;~Ezjb)88I+!B7fX1(i7df+^q9kdbeqTPRw!x8a+gHo z1;fZ`?c6-3S_!-|?@#HBgTL6rW!j35o#Yu-F4amsDsUL0-krJ%vQ{qlD^S#ay1XmM zXvDRDO*>-NMrOh%TR($XqLkdz?g)dA+RZLH!u9vn&{L=bM!)WG0$dTw1W#Q+rn_U>vXMVJ{U(HDy*&HpB2R6?!MLK|N~ zJn_Qi8-yWK* zCSc+G$E*d0o(UoP(2kevFRnQjM)_VZBd`U zqBJ|e(aQ{GDD1_CcjmgBwPZqcRnKBiHo?hc%8x1JuLrR{Y|}+#eUawXrv_h zNogsLv^31Uk6I<|QGp|egxhRo6$h5u&R6@DUj{9(#~U|fiHNh=SvmWx=1U!>s*`@Azh~iK&Cq(0Le?3w*pxgd@N6Y+jRqa-=s?#LO zwZsVY2EfN0pulrqmN9OK8Z+9L?^i2c7V zGqKK$kHe(c#p{JRakKOObvA@;#PPb5;u2>*%s@=#f#FokD5ZuJAk@XFE}`GX#s9x zuT~cQN%%B?@6BIdnSH`wVTUys7D4nl-Z}3vMkll&+v(+=rOj34!ZZ6(U;+aic~otm z%$I+)gA)QvH(=E!6t9!)_E4ER`dV#;(_;HTp~o#HHU>>Zg08JLUs6tzMVyNO4}*YA zGvJ?$($#s;qC}L1yq3I8q9wsHqE!D43fRE=1p~HUYFA!6&n^v z;)K7=AlFI_Uw@A(kC|#C zR;D{3r9u|ovOT|?dxV733HuO0!HwBP%bB-f_E+uG{kU-4JUSNjD3#G#&!!*q2)hG_J3{rnzVub2 zw|>-pJNxlHXLH3uyZNt^R=5e)z+?Oh(%>-^9FMtXg~ePx36yBPFPUc0{epYSn9EtM z1WXPkKUc*V>XSP(iYxEd_qGNP+fyu9Ab~eV1rJUd%z_pXC9aq zO;|Xf%S1uAK7DKyf63IA7J8s;3KqyD%WpSH=IQIUw)sb+*l&>7T1$4`J{@< zE@nANZX{l$z)#Aj$G8WkaDLbbBiQH~*NCS4-|;xnMRCxw#F>x^D86@Jht zbwcEpow#x|=XsY;lX|?%6}BIQtn`@L>#lSD&sl>y9ZbPi3_`5>tqps4iH<-XI;@tO z%lAPP)b}C;cx`uB0000-m=1{NSh51c_L39|0+nAD;J=;hKc_4DV>empo;0FI4-T|Z z!Fc#JXjjy3h<6%136_jRiK4yZ-Es#ol}v?%7Y*-fyKq$_@S~OLJ@l^zOkbT$g10}~ z9jdyVfo)AixHOKaTB}{;+BGBheqe@%rl3IaIdSxx@ug#=Ow|n&gMDW1O-}~e6eem@ znXAW$`t`;yV?}13MSSx8Qmvaf=@_{@9Z%)lLgO+<#QI!#=zJQLXv@GN2vIdos@!T^ zmidy35!i83o~ zd0XVBGE7eI;T*MNz(%QPsGCgxkG}@_MVW@^P5u0kxLR*bxWK-8bL;EY zXoMF-lxm$jmVjv)k>0jY|6f{e;lS0hhVSN6aiH&fneawOiqQ zA+3F*_JFZ=$i}o8w#24SDy7|%a z&qnPFCWys#Wxu>QI%AjETa9#Pv+={TkHu>igP~2_@3+)aF59t;d#WOPo(xSPMRZ8P zS4qfh(VG#qb?iOr;FJ1Wbd z6>Ds-!4KV|^#FK0i3M^U-=I?#T0RAKC7=~TkEI79R!R;U>7hxFa(6!p#hU*nHX~hc zKbm?@T+2Mnae`aYCeQgh?j)!OuCoKtR`SRZcS7*9qRDHTD3OkGpT&pLyDzCbk*D+> zGc;uXnjja62VD7ALxAHxCHid)0Weok-u|d(%dW-s%H@J{cK6^n9y`1es&(J(^TWZ5 zV#FMU%zesiy@iBz9!D%nqg#6Q$g0%(dhG7G^{o-jCIo#5Wp++A2$E0g_z`!f6vZgk zIVLP1lV;WK9J>wo74cbmaJRWKbu~}N%=_>DbHC^lap`q%-BFH9xUkm>56x1rolG`k zmAidELiL{yi^WtP$+*n6+gp%C(Kn+z7cc3i0qdyh1&ERO*_I56Vg$oP3^rjh#J`aO zs&M4Lrcf9?qMsOBV}qi9O@%tku%sC|1fS9HB-?ylwhl$Nx6|gMOpjUMx z`cR7|10pGBik%bfON;IO>lflJ=pC<+77dNG@(=@UJq{AUzMg?QO1{ZCOQm?X>TMcF zI-PNq^!@+?L8b)#b&FZ<6u|kc%rQg%9aPAVSR$?i*(DHc_!V$Rh}URQHT&308(Maf zzNgO1lF!>&yY-7nRQ7BOnhbe3cuD6uK-fzEM=Umrc!PDMhSVyWi?$-+FA;mu$wJI` za1G_$FFYtf4%0k8gbe}`e5yCsBw4#D&uV$e-<&4kLQK|RNnpyT^Yg&7WxSyWSE+V4 zIX5NCu+BgaYDxs;uj%uh*Sb_2H32`tsa!Kj%~UW|+3>HJf^Ob_?<=EKLGk1d6Tv_7 zF7C0|t~82IM-8K>3naP>I1-iFTW*!;YBJy?X`ZhzeMqV=g3#|aC5I*yc`Q|6u z-A=KS~_ul8m>N)6nIxR}e_;4{K(9193V?2#f& z4_H1w!x?s>mG++-5Y~o2k57&~1KRueK&Xp7O(09TnS04d-Gz6iVirj};Pm=JWMepJ z2te}fHe>=$&)jaY^lj>&cOa)_tIypCIMS@c7^8=qaQ?8t%~4$-4&Zs!F(u(VEjMcY zIS4#>~bI?{CF;}%#F7vrVoHuo_?!<**$8WV@*yE z6_h4>zSFksrnvPBANzx^6tB;6{Vs~Wmf(ShaA#?GLGX+R%_vQ;=xx$da3Chz&t@b6 zVHDQINpry^Qh4wC!03* zcHfxY&nimv%$(dC;*iVslDE_1A&*J1?s-9>fe}y_JRrbWmMON^P9zY9j2%$LXysgx zVw~VoZxI(;Qi2KI8RK_sW9Y;;l;vgo&+!8AG9A<$<(v5i>r~o3xCvgHyv9>TCy;d` z=v-!d5Def4+#O(s6Y`G&Bl2_vuhFuybVg)uwq3QTl%9cw4gGH7CZn*{ytvS>bP}&T z-D5s1ae?Loiw1d~+G#!WXO<^MVxn(idEJtH{UtkfEgv5YOUB);gSj$8mYdb24IZf4 zg{3#$#KxsmJmXOQWibUYy!|-9;0$GTqzzh;yEvAatj8nmKO>AvoJXw1*@qI8XV{ z!`y`UaZjf!0e!1bur}k;QtAXj)*2IK=25_(H0ef!2auq|-4yRD-U4X88WV^auU7zGF*#ni+arJWj z*di=m;eBhFO5Bf$T&y+ zhwlJw4qc1Wp0+kT;tj~=HaGLQl=hS(5+i-T&@145<^v-k+;Sa6r_BUp zAmWd-{mKTcvj!nI1}R=ALrDmX9xW~pLF$tyGD7OoXUQ9QY!RE*cJe>JT627d(8!v> z+rK#y!YR{mB_ybcN~G@GZgbkL$O{k8vVjcSd%(B{Bm?L=71NGy@;leKNUN7esP}ek zJ7-^)C=d>FzU1`s5rX~{fw$%$L#cb=WVtTXA(}9*Lhb@`0X!}XzcuprYZLkKeWRPq z2mx2ACX{H_=5L2zuwEk~N@o>jrvrd=OE3~F=tJ6ZEa~acDBa*7*4O)4v4!|4o7V~5 z_9U!E8LhfdBumx&EaLWBpw?GPbcLAL3Cw_K7O8POwkzKlh)A9Ho(gskJ*o$Y-4aUP zINGKd9D@>2aK$2*G&oFb40l$NS1mpkF8;Q?Gwh+c42rlp1lq=fld`kTmX0`z;oYM zErBH!h>E57gaz0Wl9D#Z`IKXcB~PJmgrY?t?A{Sgtc%agR0000000h(k000>T0002VVQ$p` literal 0 HcmV?d00001 diff --git a/docs/dev-guide/adding-grid-support/index.md b/docs/dev-guide/adding-grid-support/index.md new file mode 100644 index 00000000000..18469e710e4 --- /dev/null +++ b/docs/dev-guide/adding-grid-support/index.md @@ -0,0 +1,8 @@ +# Adding Support for New Grids + + + + +- [Atmosphere Grid Overview ](adding-grid-support-SE-grid-overview.md) +- [Grid Description File Overview ](adding-grid-support-grid-types.md) +- [Step-by-Step Guide to Support a new Grid ](adding-grid-support-step-by-step-guide.md) diff --git a/docs/development.md b/docs/development.md index 9b1e171a972..1c5ddf452df 100644 --- a/docs/development.md +++ b/docs/development.md @@ -11,3 +11,4 @@ More information + [Development Big Picture](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/7997024/Development+Big+Picture) + [Getting Started](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/1868455/Development+Getting+Started+Guide) + [Development Reference](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/2523163/Development+Reference) ++ [Adding Support for New Grids](dev-guide/adding-grid-support/index.md) \ No newline at end of file From eb456bddff699faa6d23fffe194603f51e586bb0 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 14 May 2024 17:12:07 -0600 Subject: [PATCH 169/388] linter fix --- .../adding-grid-support/adding-grid-support-grid-types.md | 2 +- docs/development.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md b/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md index 036312a4663..d1179f0022c 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-grid-types.md @@ -10,4 +10,4 @@ Less common “GLL” metadata files needed for specialized purposes: - **"latlon" file**: ex. "ne4np4_latlon.nc". This file contains a list of all the GLL nodes in the mesh (in latitude/longitude coordinates). The list of GLL nodes must be in the the internal HOMME global id ordering, matching the ordering used in EAM GLL grid output. It also contains the connectivity of the GLL subcell grid. This file is no longer needed for any E3SM workflow. -- **"pentagons" file**: ex. "ne30np4_pentagons.nc". These files represent a mostly outdated approach of dealing with data on the np4 grid. While the np4 grid provides a spectral element representation of data with weights on GLL nodes, the term "dual grid" refers to a finite volume approximation of the same data by constructing polygons around each GLL node such that the cell area matches the weight of each node. The word "pentagons" was used because that is the most number of sides used by the polygons. These files are increasingly difficult to generate as the global resolution becomes finer because the polygon construction is a costly iterative process. Some tools to generate these files were either the NCL code `HOMME2SCRIP.ncl` or the matlab code `dualgridgenerate.m`. These types of files are no longer needed for any E3SM workflow, although some of these files can still be found in the E3SM data repository. \ No newline at end of file +- **"pentagons" file**: ex. "ne30np4_pentagons.nc". These files represent a mostly outdated approach of dealing with data on the np4 grid. While the np4 grid provides a spectral element representation of data with weights on GLL nodes, the term "dual grid" refers to a finite volume approximation of the same data by constructing polygons around each GLL node such that the cell area matches the weight of each node. The word "pentagons" was used because that is the most number of sides used by the polygons. These files are increasingly difficult to generate as the global resolution becomes finer because the polygon construction is a costly iterative process. Some tools to generate these files were either the NCL code `HOMME2SCRIP.ncl` or the matlab code `dualgridgenerate.m`. These types of files are no longer needed for any E3SM workflow, although some of these files can still be found in the E3SM data repository. diff --git a/docs/development.md b/docs/development.md index 1c5ddf452df..0248bed09b7 100644 --- a/docs/development.md +++ b/docs/development.md @@ -11,4 +11,4 @@ More information + [Development Big Picture](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/7997024/Development+Big+Picture) + [Getting Started](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/1868455/Development+Getting+Started+Guide) + [Development Reference](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/2523163/Development+Reference) -+ [Adding Support for New Grids](dev-guide/adding-grid-support/index.md) \ No newline at end of file ++ [Adding Support for New Grids](dev-guide/adding-grid-support/index.md) From c9871408a76eb933fdb0edee4e755ca38a03025e Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 2 Apr 2024 10:29:59 -0400 Subject: [PATCH 170/388] Adding hooks for history dimension control in fates --- components/elm/bld/ELMBuildNamelist.pm | 5 +- .../bld/namelist_files/namelist_defaults.xml | 2 +- .../namelist_files/namelist_definition.xml | 13 ++ components/elm/src/main/controlMod.F90 | 6 +- components/elm/src/main/elm_varctl.F90 | 15 +- .../elm/src/main/elmfates_interfaceMod.F90 | 143 +++++++++++++++--- components/elm/src/main/histFileMod.F90 | 2 +- 7 files changed, 156 insertions(+), 30 deletions(-) diff --git a/components/elm/bld/ELMBuildNamelist.pm b/components/elm/bld/ELMBuildNamelist.pm index c6214323525..250d8666d25 100755 --- a/components/elm/bld/ELMBuildNamelist.pm +++ b/components/elm/bld/ELMBuildNamelist.pm @@ -798,7 +798,7 @@ sub setup_cmdl_fates_mode { "use_fates_inventory_init", "use_fates_fixed_biogeog", "use_fates_nocomp","use_fates_sp", "fates_inventory_ctrl_filename","use_fates_logging", "use_fates_tree_damage", "use_fates_parteh_mode","use_fates_cohort_age_tracking","use_snicar_ad", "use_fates_luh", - "fluh_timeseries"); + "fluh_timeseries","fates_history_dimlevel"); foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { $nl_flags->{$var} = $nl->get_value($var); @@ -3300,7 +3300,8 @@ sub setup_logic_fates { add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_luh', 'use_fates'=>$nl_flags->{'use_fates'}); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fluh_timeseries', 'phys'=>$nl_flags->{'phys'}); - + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_history_dimlevel','use_fates'=>$nl_flags->{'use_fates'}); + # For FATES SP mode make sure no-competion, and fixed-biogeography are also set # And also check for other settings that can't be trigged on as well my $var = "use_fates_sp"; diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 8294fdeeb5a..23d05a8f772 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -2191,7 +2191,7 @@ this mask will have smb calculated over the entire global land surface .false. .true. .false. - +2,2 .true. .true. .false. diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 0f8b03dfec3..955fddcdb79 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -395,6 +395,19 @@ Full pathname of unified land use harmonization data file. This causes the land- types to vary over time. + +Setting for what types of FATES history to be allocate and +calculated at the dynamics timestep (1st integer) and the +model timestep (2nd integer). This must be consistent with +hist_fincl*, ie output variables must not be listed if the +output level is not enabled. +0 = no fates history variables are calculated or allocated +1 = only time x space (3d) fates history variables allowed +2 = multiplexed dimensioned fates history is also allowed +(Only relevant if FATES is on) + + Toggle to turn on if Kennedy et al plant hydraulics model is used. diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 3b8c08be31b..8f763a9ebd4 100755 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -263,7 +263,8 @@ subroutine control_init( ) fluh_timeseries, & fates_parteh_mode, & fates_seeddisp_cadence, & - use_fates_tree_damage + use_fates_tree_damage, & + fates_history_dimlevel namelist /elm_inparm / use_betr @@ -818,7 +819,8 @@ subroutine control_spmd() call mpi_bcast (fates_parteh_mode, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (fates_seeddisp_cadence, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (use_fates_tree_damage, 1, MPI_LOGICAL, 0, mpicom, ier) - + call mpi_bcast (fates_history_dimlevel, 2, MPI_INTEGER, 0, mpicom, ier) + call mpi_bcast (use_betr, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_lai_streams, 1, MPI_LOGICAL, 0, mpicom, ier) diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index d5a61da8fdb..7fa580b19f2 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -240,7 +240,20 @@ module elm_varctl integer, public :: fates_seeddisp_cadence = iundef ! 0 => no seed dispersal across gridcells ! 1, 2, 3 => daily, monthly, or yearly seed dispersal - + ! FATES history dimension level + ! fates can produce history at either the daily timescale (dynamics) + ! and the model step timescale. It can also generate output on the extra dimension + ! Performing this output can be expensive, so we allow different history dimension + ! levels. + ! The first index is output at the model timescale + ! The second index is output at the dynamics (daily) timescale + ! 0 - no output + ! 1 - include only column level means (3D) + ! 2 - include output that includes the 4th dimension + + integer, dimension(2), public :: fates_history_dimlevel = (/2,2/) + + !---------------------------------------------------------- ! BeTR switches !---------------------------------------------------------- diff --git a/components/elm/src/main/elmfates_interfaceMod.F90 b/components/elm/src/main/elmfates_interfaceMod.F90 index 9b9fbc6e390..bb8b8d93dc4 100644 --- a/components/elm/src/main/elmfates_interfaceMod.F90 +++ b/components/elm/src/main/elmfates_interfaceMod.F90 @@ -59,6 +59,7 @@ module ELMFatesInterfaceMod use elm_varctl , only : use_fates_tree_damage use elm_varctl , only : nsrest, nsrBranch use elm_varctl , only : fates_inventory_ctrl_filename + use elm_varctl , only : fates_history_dimlevel use elm_varctl , only : use_lch4 use elm_varctl , only : use_century_decomp use elm_varcon , only : tfrz @@ -137,7 +138,7 @@ module ELMFatesInterfaceMod use FatesHistoryInterfaceMod, only : fates_hist use FatesRestartInterfaceMod, only : fates_restart_interface_type use FatesInterfaceTypesMod, only : hlm_num_luh2_states - + use FatesIOVariableKindMod, only : group_dyna_simple, group_dyna_complx use PRTGenericMod , only : num_elements use FatesPatchMod , only : fates_patch_type use FatesDispersalMod , only : lneighbors, dispersal_type, IsItDispersalTime @@ -284,6 +285,7 @@ module ELMFatesInterfaceMod public :: ELMFatesGlobals1 public :: ELMFatesGlobals2 public :: ELMFatesTimesteps + public :: CrossRefHistoryFields contains @@ -427,6 +429,9 @@ subroutine ELMFatesGlobals2() call set_fates_ctrlparms('parteh_mode',ival=fates_parteh_mode) call set_fates_ctrlparms('seeddisp_cadence',ival=fates_seeddisp_cadence) + call set_fates_ctrlparms('hist_hifrq_dimlevel',ival=fates_history_dimlevel(1)) + call set_fates_ctrlparms('hist_dynam_dimlevel',ival=fates_history_dimlevel(2)) + if(use_fates_tree_damage)then pass_tree_damage = 1 else @@ -590,6 +595,84 @@ subroutine ELMFatesGlobals2() return end subroutine ELMFatesGlobals2 + + ! =================================================================================== + + subroutine CrossRefHistoryFields + + ! This routine only needs to be called on the masterproc. + ! Here we cross reference the ELM history master + ! list and make sure that all fields that start + ! with fates have been allocated. If it has + ! not, then we give a more constructive error + ! message than what is possible in PIO. The user + ! most likely needs to increase the history density + ! level + + use histFileMod, only: getname + use histFileMod, only: hist_fincl1,hist_fincl2,hist_fincl3,hist_fincl4 + use histFileMod, only: hist_fincl5,hist_fincl6 + use histFileMod, only: max_tapes, max_flds, max_namlen + + integer :: t ! iterator index for history tapes + integer :: f ! iterator index for registered history field names + integer :: nh ! iterator index for fates registered history + logical :: is_fates_field ! Does this start with FATES_ ? + logical :: found ! if true, than the history field is either + ! not part of the fates set, or was found in + ! the fates set + character(len=64) :: fincl_name + ! This is a copy of the public in histFileMod, copied + ! here because it isn't filled at the time of this call + character(len=max_namlen+2) :: fincl(max_flds,max_tapes) + + fincl(:,1) = hist_fincl1(:) + fincl(:,2) = hist_fincl2(:) + fincl(:,3) = hist_fincl3(:) + fincl(:,4) = hist_fincl4(:) + fincl(:,5) = hist_fincl5(:) + fincl(:,6) = hist_fincl6(:) + + do t = 1,max_tapes + + f = 1 + search_fields: do while (f < max_flds .and. fincl(f,t) /= ' ') + + fincl_name = getname(fincl(f,t)) + is_fates_field = fincl_name(1:6)=='FATES_' + + if(is_fates_field) then + found = .false. + do_fates_hist: do nh = 1,fates_hist%num_history_vars() + if(trim(fates_hist%hvars(nh)%vname) == & + trim(fincl_name)) then + found=.true. + exit do_fates_hist + end if + end do do_fates_hist + + if(.not.found)then + write(iulog,*) 'the history field: ',trim(fincl_name) + write(iulog,*) 'was requested in the namelist, but was' + write(iulog,*) 'not found in the list of fates_hist%hvars.' + write(iulog,*) 'Most likely, this is because this history variable' + write(iulog,*) 'was specified in the user namelist, but the user' + write(iulog,*) 'specified a FATES history output dimension level' + write(iulog,*) 'that does not contain that variable in its valid set.' + write(iulog,*) 'You may have to increase the namelist setting: fates_history_dimlevel' + write(iulog,*) 'current fates_history_dimlevel: ',fates_history_dimlevel(:) + !uncomment if you want to list all fates history variables in registry + !do_fates_hist2: do nh = 1,fates_hist%num_history_vars() + ! write(iulog,*) trim(fates_hist%hvars(nh)%vname) + !end do do_fates_hist2 + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + end if + f = f + 1 + end do search_fields + + end do + end subroutine CrossRefHistoryFields ! ==================================================================================== @@ -1097,11 +1180,8 @@ subroutine dynamics_driv(this, bounds_clump, top_as_inst, & ! Flush arrays to values defined by %flushval (see registry entry in ! subroutine define_history_vars() ! --------------------------------------------------------------------------------- - call fates_hist%flush_hvars(nc,upfreq_in=1) - - ! Frequency 5 is routine that processes FATES history - ! on the dynamics (daily) step, but before disturbance - call fates_hist%flush_hvars(nc,upfreq_in=5) + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_simple) + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_complx) ! --------------------------------------------------------------------------------- ! Part II: Call the FATES model now that input boundary conditions have been @@ -1791,14 +1871,22 @@ subroutine restart( this, bounds_proc, ncid, flag, & ! ------------------------------------------------------------------------ ! Update history IO fields that depend on ecosystem dynamics ! ------------------------------------------------------------------------ - call fates_hist%flush_hvars(nc,upfreq_in=1) - call fates_hist%flush_hvars(nc,upfreq_in=5) - do s = 1,this%fates(nc)%nsites - call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & - upfreq_in=1) - call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & - upfreq_in=5) - end do + + if(fates_history_dimlevel(2)>0) then + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_simple) + do s = 1,this%fates(nc)%nsites + call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & + upfreq_in=group_dyna_simple) + end do + if(fates_history_dimlevel(2)>1) then + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_complx) + do s = 1,this%fates(nc)%nsites + call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & + upfreq_in=group_dyna_complx) + end do + end if + end if + call fates_hist%update_history_dyn( nc, & this%fates(nc)%nsites, & this%fates(nc)%sites, & @@ -1971,15 +2059,21 @@ subroutine init_coldstart(this, canopystate_inst, soilstate_inst, frictionvel_in ! ------------------------------------------------------------------------ ! Update history IO fields that depend on ecosystem dynamics ! ------------------------------------------------------------------------ - - call fates_hist%flush_hvars(nc,upfreq_in=1) - call fates_hist%flush_hvars(nc,upfreq_in=5) - do s = 1,this%fates(nc)%nsites - call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & - upfreq_in=1) - call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & - upfreq_in=5) - end do + if(fates_history_dimlevel(2)>0) then + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_simple) + do s = 1,this%fates(nc)%nsites + call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & + upfreq_in=group_dyna_simple) + end do + if(fates_history_dimlevel(2)>1) then + call fates_hist%flush_hvars(nc,upfreq_in=group_dyna_complx) + do s = 1,this%fates(nc)%nsites + call fates_hist%zero_site_hvars(this%fates(nc)%sites(s), & + upfreq_in=group_dyna_complx) + end do + end if + end if + call fates_hist%update_history_dyn( nc, & this%fates(nc)%nsites, & this%fates(nc)%sites, & @@ -2762,6 +2856,7 @@ subroutine wrap_update_hifrq_hist(this, bounds_clump ) this%fates(nc)%nsites, & this%fates(nc)%sites, & this%fates(nc)%bc_in, & + this%fates(nc)%bc_out, & dtime) @@ -3068,6 +3163,8 @@ subroutine init_history_io(this,bounds_proc) call fates_hist%initialize_history_vars() nvar = fates_hist%num_history_vars() + call CrossRefHistoryFields() + do ivar = 1, nvar associate( vname => fates_hist%hvars(ivar)%vname, & diff --git a/components/elm/src/main/histFileMod.F90 b/components/elm/src/main/histFileMod.F90 index c11eafe96f4..1b86c3a1618 100644 --- a/components/elm/src/main/histFileMod.F90 +++ b/components/elm/src/main/histFileMod.F90 @@ -148,7 +148,7 @@ module histFileMod private :: hist_set_snow_field_2d ! Set values in history field dimensioned by levsno private :: list_index ! Find index of field in exclude list private :: set_hist_filename ! Determine history dataset filenames - private :: getname ! Retrieve name portion of input "inname" + public :: getname ! Retrieve name portion of input "inname" (PUBLIC for FATES) private :: getflag ! Retrieve flag private :: pointer_index ! Track data pointer indices private :: max_nFields ! The max number of fields on any tape From 93a0c8b8fa20d07983149308bf5439c5e4374256 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Wed, 15 May 2024 09:40:37 -0400 Subject: [PATCH 171/388] Updated fates external pointer to sci.1.76.3_api.35.1.0 --- components/elm/src/external_models/fates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/src/external_models/fates b/components/elm/src/external_models/fates index 42d804ba54d..f0185f7c703 160000 --- a/components/elm/src/external_models/fates +++ b/components/elm/src/external_models/fates @@ -1 +1 @@ -Subproject commit 42d804ba54d0cf013a9737018ff9920e0c9808ea +Subproject commit f0185f7c7033fa69c80d1ddb07cbcbf1f8be1adc From 3f981e2da203761406df98276a101655d20770e0 Mon Sep 17 00:00:00 2001 From: Hannah Date: Wed, 15 May 2024 10:37:34 -0600 Subject: [PATCH 172/388] reorganize dev-guide --- .../eam/docs/figures}/grid_illustration_ne4np4.png | Bin .../eam/docs/figures}/grid_illustration_ne4pg2.png | Bin .../eam/docs/tech-guide/atmosphere-grid-overview.md | 4 ++-- docs/dev-guide/adding-grid-support/index.md | 3 ++- docs/{development.md => dev-guide/index.md} | 2 +- docs/index.md | 2 +- mkdocs.yaml | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) rename {docs/dev-guide/adding-grid-support => components/eam/docs/figures}/grid_illustration_ne4np4.png (100%) rename {docs/dev-guide/adding-grid-support => components/eam/docs/figures}/grid_illustration_ne4pg2.png (100%) rename docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md => components/eam/docs/tech-guide/atmosphere-grid-overview.md (93%) rename docs/{development.md => dev-guide/index.md} (89%) diff --git a/docs/dev-guide/adding-grid-support/grid_illustration_ne4np4.png b/components/eam/docs/figures/grid_illustration_ne4np4.png similarity index 100% rename from docs/dev-guide/adding-grid-support/grid_illustration_ne4np4.png rename to components/eam/docs/figures/grid_illustration_ne4np4.png diff --git a/docs/dev-guide/adding-grid-support/grid_illustration_ne4pg2.png b/components/eam/docs/figures/grid_illustration_ne4pg2.png similarity index 100% rename from docs/dev-guide/adding-grid-support/grid_illustration_ne4pg2.png rename to components/eam/docs/figures/grid_illustration_ne4pg2.png diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md b/components/eam/docs/tech-guide/atmosphere-grid-overview.md similarity index 93% rename from docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md rename to components/eam/docs/tech-guide/atmosphere-grid-overview.md index 29f2e895430..0184a2d96b6 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-SE-grid-overview.md +++ b/components/eam/docs/tech-guide/atmosphere-grid-overview.md @@ -11,7 +11,7 @@ While the atmosphere history output is primarily on the physics grid (see below) For a np4 grid with N elements per cube edge the total number of unique GLL nodes can be calculated as: `N*(np-1)^2 + 2` -![ne4np4 grid illustration](grid_illustration_ne4np4.png) +![ne4np4 grid illustration](../figures/grid_illustration_ne4np4.png) ## The pg2 "physgrid" @@ -20,4 +20,4 @@ Starting in v2, physics calculations and history output in E3SM use a quasi-equa For a pg2 grid with N elements per cube edge the total number of physics columns can be calculated as: `ncol = N*N*6*(2*2)` -![ne4pg2 grid illustration](grid_illustration_ne4pg2.png) +![ne4pg2 grid illustration](../figures/grid_illustration_ne4pg2.png) diff --git a/docs/dev-guide/adding-grid-support/index.md b/docs/dev-guide/adding-grid-support/index.md index 18469e710e4..81f8a1e2c15 100644 --- a/docs/dev-guide/adding-grid-support/index.md +++ b/docs/dev-guide/adding-grid-support/index.md @@ -3,6 +3,7 @@ -- [Atmosphere Grid Overview ](adding-grid-support-SE-grid-overview.md) + +- [Atmosphere Grid Overview ](/EAM/tech-guide/atmosphere-grid-overview) - [Grid Description File Overview ](adding-grid-support-grid-types.md) - [Step-by-Step Guide to Support a new Grid ](adding-grid-support-step-by-step-guide.md) diff --git a/docs/development.md b/docs/dev-guide/index.md similarity index 89% rename from docs/development.md rename to docs/dev-guide/index.md index 0248bed09b7..e05e7b150bf 100644 --- a/docs/development.md +++ b/docs/dev-guide/index.md @@ -11,4 +11,4 @@ More information + [Development Big Picture](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/7997024/Development+Big+Picture) + [Getting Started](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/1868455/Development+Getting+Started+Guide) + [Development Reference](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/2523163/Development+Reference) -+ [Adding Support for New Grids](dev-guide/adding-grid-support/index.md) ++ [Adding Support for New Grids](adding-grid-support/index.md) diff --git a/docs/index.md b/docs/index.md index 4bc48af94a5..af7e652d652 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ research problems and Department of Energy mission needs while efficiently using - [Installation](installation.md) - [User Guide](user-guide/index.md) -- [Development](development.md) +- [Development](dev-guide/index.md) ## Component Models diff --git a/mkdocs.yaml b/mkdocs.yaml index 3c7a2f93bdb..9ce3e371331 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -6,7 +6,7 @@ nav: - 'index.md' - Installation: 'installation.md' - User Guide: 'user-guide/index.md' - - Development: 'development.md' + - Development: 'dev-guide/index.md' - Components: '*include ./components/*/mkdocs.yml' - Tools: '*include ./tools/*/mkdocs.yml' - More Information: From dbfadc9ba0d4d50d5678419d46fdec7e5d70f572 Mon Sep 17 00:00:00 2001 From: Hannah Date: Thu, 16 May 2024 11:08:24 -0600 Subject: [PATCH 173/388] initial version of topo generation workflow --- .../generate-topo-file.md | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index 47ba4345d0b..347826f0c76 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -1 +1,147 @@ # Generate a Topography File + +Topography needs to be interpolated from a high resolution USGS file, and then doctored up a bit to allow the model to run stably with the new topography. The tool chain used to compute topography is documented in the following paper: + +[P.H. Lauritzen, J.T. Bacmeister, P.F. Callaghan, M. Taylor, NCAR_Topo (v1.0): NCAR global model topography generation software for unstructured grids, Geosci. Model Dev., 8, 3975-3986, 2015.](https://www.geosci-model-dev.net/8/3975/2015/) + +## Input Topography Data + +Traditionally the topography generation for E3SM start with **USGS-topo-cube3000.nc**, which is a high-resolution topography dataset on a 3km cubed sphere grid derived from 1 km resolution source data. This file is located in the [CESM inputdata server here](https://svn-ccsm-inputdata.cgd.ucar.edu/trunk/inputdata/atm/cam/hrtopo/). + +For target resolutions of 3 km or finer it is recommended to use **USGS-topo-cube12000.nc**, which was created by Jishi Zhang in 2024. This file has a resolution of 750m created from a 500m/250m USGS GMTED2010 source DEM dataset (see [here](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/4189520033/800m+cubed+topo+generation+from+GMTED2010+15s+DEM) for more information). + +## homme_tool + +homme_tool is included in the repository (`components/homme/test/tool`). This builds parts of the HOMME code directly, which is preferred to creating an offline tool. This tool allows us to process the topography data and address the following requirements: + +- The dycore needs surface geopotential (`phi_s`) at GLL nodes (np4) +- The physics needs various things at FV cell centers (pg2) + - surface geopotential (`phi_s`) + - sub-grid variance of topography (`SGH` and `SGH30`) + - Land area fraction (`LANDFRAC`) +- The np4 to pg2 map of `phi_s` data must be equal to the FV `phi_s` data +- HOMME's smoothing operator must be used on `phi_s` for stability + +## Step-by-Step Topography Generation + +1. Set some helpful environmental variables used in commands below + ```shell + e3sm_root= + grid_root= + map_root= + topo_root= + + NE= + ``` + ```shell + e3sm_root=/lustre/orion/cli115/proj-shared/hannah6/e3sm_scratch/tmp_clone + grid_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_grid + map_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_map + topo_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_topo + + NE=30 + + e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone + grid_root=/pscratch/sd/w/whannah/e3sm_scratch/files_grid + map_root=/pscratch/sd/w/whannah/e3sm_scratch/files_map + topo_root=/pscratch/sd/w/whannah/e3sm_scratch/files_topo + + e3sm_root=/lcrc/group/e3sm/ac.whannah/scratch/chrys/tmp_clone + grid_root=/pscratch/sd/w/whannah/e3sm_scratch/files_grid + map_root=/pscratch/sd/w/whannah/e3sm_scratch/files_map + topo_root=/pscratch/sd/w/whannah/e3sm_scratch/files_topo + ``` + +1. Set machine specific environment (this sets `DIN_LOC_ROOT`) + ```shell + cd ${e3sm_root}/components/homme + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ${e3sm_root}/cime/CIME/scripts/configure --macros-format Makefile --mpilib mpi-serial + source .env_mach_specific.sh + # above approach is too slow - will this work? + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh + ``` + +1. Create grid files for the input high res topo + ```shell + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertExodusToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + ``` + +1. Create grid files target EAM grid + ```shell + GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + ``` + +1. Create map file + ```shell + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc + ``` + +1. Map high-res topo to target np4 grid + ```shell + map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc + ncremap -m ${map_file} -i ${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc -o ${topo_root}/USGS-topo_ne${NE}np4.nc + ``` + +1. Build homme_tool + ```shell + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh + + cd ${e3sm_root}/components/homme + + E3SM_MACH=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 1 -d _ ) + E3SM_COMP=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 2 -d _ ) + + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-nocuda-gnu.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/crusher-gpumpi.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake + mach_file=${e3sm_root}/cime_config/machines/cmake_macros/gnu_chrysalis.cmake + # E3SM_MACH=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 1 -d _ ) + # E3SM_COMP=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 2 -d _ ) + # mach_file=${e3sm_root}/cime_config/machines/cmake_macros/${E3SM_COMP}_${E3SM_MACH}.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/${E3SM_MACH}.cmake + cmake -C ${mach_file} -DBUILD_HOMME_WITHOUT_PIOLIBRARY=OFF -DPREQX_PLEV=26 ${e3sm_root}/components/homme/ + make -j4 homme_tool + ``` + +1. run homme_tool + ```shell + cat < input.nl + &ctl_nl + ne = ${NE} + mesh_file = "${grid_root}/exodus_ne${NE}.g" + smooth_phis_p2filt = 0 + smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing + smooth_phis_nudt = 4e-16 + hypervis_scaling = 2 + se_ftype = 2 ! actually output NPHYS; overloaded use of ftype + / + &vert_nl + / + &analysis_nl + tool = 'topo_pgn_to_smoothed' + infilenames = '${topo_root}/USGS-topo_${NE}np4.nc', '${topo_root}/USGS-topo_${NE}np4_smoothed' + / + EOF + + mpirun -np 8 ~/E3SM/E3SM_SRC4/components/homme/src/tool/homme_tool < input.nl + ``` + +1. Compute phi_s on the np4 grid + +1. Use homme_tool to apply dycore specific smoothing on GLL grid. + +1. Compute SGH, SGH30, LANDFRAC, and LANDM_COSLAT on the pg2 grid, using the pg2 phi_s data. + +1. Append the GLL phi_s data to the output of step 4. + + + + + From 0536a0188939bc381f643bde7b61c123035a28ed Mon Sep 17 00:00:00 2001 From: Chloe Date: Fri, 17 May 2024 10:51:57 -0700 Subject: [PATCH 174/388] commented out if statements for snow history fields --- components/elm/src/data_types/VegetationDataType.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index 7a3164a75b0..45dc063b853 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -5494,20 +5494,20 @@ subroutine veg_wf_init(this, begp, endp) avgflag='A', long_name='excess rainfall due to snow capping', & ptr_patch=this%qflx_snwcp_liq, c2l_scale_type='urbanf', default='inactive') - if (use_cn) then + !if (use_cn) then this%qflx_rain_grnd(begp:endp) = spval call hist_addfld1d (fname='QFLX_RAIN_GRND', units='mm H2O/s', & avgflag='A', long_name='rain on ground after interception', & ptr_patch=this%qflx_rain_grnd, default='inactive', c2l_scale_type='urbanf') - end if + !end if - if (use_cn) then + !if (use_cn) then this%qflx_snow_grnd(begp:endp) = spval call hist_addfld1d (fname='QFLX_SNOW_GRND', units='mm H2O/s', & avgflag='A', long_name='snow on ground after interception', & ptr_patch=this%qflx_snow_grnd, default='inactive', c2l_scale_type='urbanf') - end if + !end if if (use_cn) then this%qflx_evap_grnd(begp:endp) = spval @@ -5537,12 +5537,12 @@ subroutine veg_wf_init(this, begp, endp) ptr_patch=this%qflx_dew_grnd, default='inactive', c2l_scale_type='urbanf') end if - if (use_cn) then + !if (use_cn) then this%qflx_sub_snow(begp:endp) = spval call hist_addfld1d (fname='QFLX_SUB_SNOW', units='mm H2O/s', & avgflag='A', long_name='sublimation rate from snow pack', & ptr_patch=this%qflx_sub_snow, default='inactive', c2l_scale_type='urbanf') - end if + !end if if (use_cn) then this%qflx_dew_snow(begp:endp) = spval From 8520cc81787be34b15f15d2c905a238836ddb60a Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 17 May 2024 15:47:52 -0600 Subject: [PATCH 175/388] topo workflow documentation updates --- .../generate-topo-file.md | 315 +++++++++++++----- 1 file changed, 236 insertions(+), 79 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index 347826f0c76..b547a7b8c79 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -6,13 +6,13 @@ Topography needs to be interpolated from a high resolution USGS file, and then d ## Input Topography Data -Traditionally the topography generation for E3SM start with **USGS-topo-cube3000.nc**, which is a high-resolution topography dataset on a 3km cubed sphere grid derived from 1 km resolution source data. This file is located in the [CESM inputdata server here](https://svn-ccsm-inputdata.cgd.ucar.edu/trunk/inputdata/atm/cam/hrtopo/). +Traditionally the topography generation for E3SM start with **USGS-topo-cube3000.nc**, which is included in the [E3SM inputdata repository]. This is a high-resolution topography dataset on a 3km cubed sphere grid derived from 1 km resolution source data. This file is located in the [CESM inputdata server here](https://svn-ccsm-inputdata.cgd.ucar.edu/trunk/inputdata/atm/cam/hrtopo/). For target resolutions of 3 km or finer it is recommended to use **USGS-topo-cube12000.nc**, which was created by Jishi Zhang in 2024. This file has a resolution of 750m created from a 500m/250m USGS GMTED2010 source DEM dataset (see [here](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/4189520033/800m+cubed+topo+generation+from+GMTED2010+15s+DEM) for more information). -## homme_tool +## Data Processing Requirements -homme_tool is included in the repository (`components/homme/test/tool`). This builds parts of the HOMME code directly, which is preferred to creating an offline tool. This tool allows us to process the topography data and address the following requirements: +The workflow to generate topography data for the atmosphere model must address the following requirements: - The dycore needs surface geopotential (`phi_s`) at GLL nodes (np4) - The physics needs various things at FV cell centers (pg2) @@ -22,96 +22,257 @@ homme_tool is included in the repository (`components/homme/test/tool`). This bu - The np4 to pg2 map of `phi_s` data must be equal to the FV `phi_s` data - HOMME's smoothing operator must be used on `phi_s` for stability +## Topography Smoothing + +Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. + +!!! NOTE + homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. + ## Step-by-Step Topography Generation -1. Set some helpful environmental variables used in commands below +1. **Set some helpful environmental variables used in commands below** ```shell e3sm_root= grid_root= map_root= topo_root= - + DIN_LOC_ROOT= NE= ``` + Example settings for Perlmutter (NERSC): ```shell - e3sm_root=/lustre/orion/cli115/proj-shared/hannah6/e3sm_scratch/tmp_clone - grid_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_grid - map_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_map - topo_root=/lustre/orion/cli115/proj-shared/hannah6/HICCUP/files_topo - + grid_root=${SCRATCH}/e3sm_scratch/files_grid + map_root=${SCRATCH}/e3sm_scratch/files_map + topo_root=${SCRATCH}/e3sm_scratch/files_topo + DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata NE=30 - - e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone - grid_root=/pscratch/sd/w/whannah/e3sm_scratch/files_grid - map_root=/pscratch/sd/w/whannah/e3sm_scratch/files_map - topo_root=/pscratch/sd/w/whannah/e3sm_scratch/files_topo - - e3sm_root=/lcrc/group/e3sm/ac.whannah/scratch/chrys/tmp_clone - grid_root=/pscratch/sd/w/whannah/e3sm_scratch/files_grid - map_root=/pscratch/sd/w/whannah/e3sm_scratch/files_map - topo_root=/pscratch/sd/w/whannah/e3sm_scratch/files_topo + ``` + Example settings for Chrysalis (ANL/LCRC): + ```shell + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + NE=30 + ``` + Make sure the directories exist: + ``` + mkdir -p ${grid_root} ${map_root} ${topo_root} ``` -1. Set machine specific environment (this sets `DIN_LOC_ROOT`) +1. **Specify all topo and map file paths for consistency** ```shell - cd ${e3sm_root}/components/homme - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ${e3sm_root}/cime/CIME/scripts/configure --macros-format Makefile --mpilib mpi-serial - source .env_mach_specific.sh - # above approach is too slow - will this work? - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc + map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc + map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc + map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc + ``` + +1. **Create grid and map files** + + 1. source the unified env + + Perlmutter (NERSC): + ```shell + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + ``` + Chrysalis (ANL/LCRC): + ```shell + source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh + ``` + + 1. Create grid files for the input high res topo + ```shell + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + ``` + + 1. Create grid files target EAM grid + ```shell + GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + ``` + + 1. Create map files + + !!!WARNING + this can take a long time + 1. from source to target np4 + ```shell + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} + ``` + 1. from source to target pg2 + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} + ``` + 1. from target to source (needed for calculating sub-grid anomalies on target grid) + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} + ``` + +1. **Create new topograpy data on target grid** + + 1. Map high-res topo to target np4 grid + ```shell + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} + ``` + + 1. Compute phi_s on the np4 grid + ```shell + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + ``` + +1. **Use homme_tool to smooth topography** + + 1. Set the machine specific environment + ```shell + cd ${e3sm_root}/components/homme + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ``` + + 1. Build homme_tool + + The build process requires the user to select the appropriate cmake file that contains machine-specific settings. + ```shell + mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake + + cmake -C ${mach_file} \ + -DBUILD_HOMME_THETA_KOKKOS=FALSE \ + -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ + -DHOMME_ENABLE_COMPOSE=FALSE \ + -DHOMME_BUILD_EXECS=FALSE \ + -DBUILD_HOMME_TOOL=TRUE \ + -DPREQX_PLEV=26 \ + ${e3sm_root}/components/homme + + make -j4 homme_tool + ``` + + 1. run homme_tool + ```shell + cat < input.nl + &ctl_nl + ne = ${NE} + mesh_file = "${grid_root}/exodus_ne${NE}.g" + smooth_phis_p2filt = 0 + smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing + smooth_phis_nudt = 4e-16 + hypervis_scaling = 2 + se_ftype = 2 ! actually output NPHYS; overloaded use of ftype + / + &vert_nl + / + &analysis_nl + tool = 'topo_pgn_to_smoothed' + infilenames = '${topo_file_2}', '${topo_file_3::-3}' + / + EOF + + mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl + ``` + +1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** + + 1. Remap smoothed topo to ne3000 grid + ```shell + ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + ``` + + 1. Append unsmoothed ne3000 data + ```shell + ncks -A ${topo_file_0} ${topo_file_4} ``` -1. Create grid files for the input high res topo + 1. Calculate anomalies on ne3000 grid + + (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) + ```shell + ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} + ``` + + 1. Remap anomalies back to target pg2 grid + ```shell + ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} + ``` + + +1. **???? Append LANDFRAC and LANDM_COSLAT ????** + +1. **Append the GLL phi_s data to the output of step 4** ```shell - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertExodusToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp + TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc + ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} ``` -1. Create grid files target EAM grid +## Batch scripts to streamline all steps + +Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). + +To submit the slurm batch job use `sbatch batch_topo_slurm.sh` + +

+ batch_topo_slurm.sh ```shell + #!/bin/bash + #SBATCH --constraint=cpu + #SBATCH --account=m3312 + #SBATCH -q regular + #SBATCH --job-name=generate_map + #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out + #SBATCH --time=24:00:00 + #SBATCH --nodes=1 + #SBATCH --mail-user=hannah6@llnl.gov + #SBATCH --mail-type=END,FAIL + + e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + + NE=30 + + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + + # Create grid files for the input high res topo + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + + # Create grid files target EAM grid GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc - ``` -1. Create map file - ```shell + # Create map file - source to target ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc - ``` -1. Map high-res topo to target np4 grid - ```shell - map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc - ncremap -m ${map_file} -i ${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc -o ${topo_root}/USGS-topo_ne${NE}np4.nc - ``` + # Create map file - target to source + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc -1. Build homme_tool - ```shell - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh - - cd ${e3sm_root}/components/homme - - E3SM_MACH=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 1 -d _ ) - E3SM_COMP=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 2 -d _ ) - - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-nocuda-gnu.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/crusher-gpumpi.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake - mach_file=${e3sm_root}/cime_config/machines/cmake_macros/gnu_chrysalis.cmake - # E3SM_MACH=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 1 -d _ ) - # E3SM_COMP=$(${e3sm_root}/cime/CIME/Tools/list_e3sm_tests cime_tiny | grep ERS | cut -f 4 -d . | cut -f 2 -d _ ) - # mach_file=${e3sm_root}/cime_config/machines/cmake_macros/${E3SM_COMP}_${E3SM_MACH}.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/${E3SM_MACH}.cmake - cmake -C ${mach_file} -DBUILD_HOMME_WITHOUT_PIOLIBRARY=OFF -DPREQX_PLEV=26 ${e3sm_root}/components/homme/ - make -j4 homme_tool - ``` + # Map high-res topo to target np4 grid + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} -1. run homme_tool - ```shell + # Compute phi_s on the np4 grid + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + + # Use homme_tool to smooth topography cat < input.nl &ctl_nl ne = ${NE} @@ -126,22 +287,18 @@ homme_tool is included in the repository (`components/homme/test/tool`). This bu / &analysis_nl tool = 'topo_pgn_to_smoothed' - infilenames = '${topo_root}/USGS-topo_${NE}np4.nc', '${topo_root}/USGS-topo_${NE}np4_smoothed' + infilenames = '${topo_file_2}', '${topo_file_3::-3}' / EOF - mpirun -np 8 ~/E3SM/E3SM_SRC4/components/homme/src/tool/homme_tool < input.nl - ``` - -1. Compute phi_s on the np4 grid - -1. Use homme_tool to apply dycore specific smoothing on GLL grid. - -1. Compute SGH, SGH30, LANDFRAC, and LANDM_COSLAT on the pg2 grid, using the pg2 phi_s data. - -1. Append the GLL phi_s data to the output of step 4. - - - + mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl + # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data + ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + ncks -A ${topo_file_0} ${topo_file_4} + ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} + ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} + + ``` +
From eaaaa8e78868fe177d8dc3e060435f954bac330c Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 17 May 2024 15:51:23 -0600 Subject: [PATCH 176/388] fix indentation for topo guide --- .../generate-topo-file.md | 448 +++++++++--------- 1 file changed, 224 insertions(+), 224 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index b547a7b8c79..e3f58ad405a 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -16,9 +16,9 @@ The workflow to generate topography data for the atmosphere model must address t - The dycore needs surface geopotential (`phi_s`) at GLL nodes (np4) - The physics needs various things at FV cell centers (pg2) - - surface geopotential (`phi_s`) - - sub-grid variance of topography (`SGH` and `SGH30`) - - Land area fraction (`LANDFRAC`) + - surface geopotential (`phi_s`) + - sub-grid variance of topography (`SGH` and `SGH30`) + - Land area fraction (`LANDFRAC`) - The np4 to pg2 map of `phi_s` data must be equal to the FV `phi_s` data - HOMME's smoothing operator must be used on `phi_s` for stability @@ -27,252 +27,138 @@ The workflow to generate topography data for the atmosphere model must address t Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. !!! NOTE - homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. + homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. ## Step-by-Step Topography Generation 1. **Set some helpful environmental variables used in commands below** - ```shell - e3sm_root= - grid_root= - map_root= - topo_root= - DIN_LOC_ROOT= - NE= - ``` - Example settings for Perlmutter (NERSC): - ```shell - grid_root=${SCRATCH}/e3sm_scratch/files_grid - map_root=${SCRATCH}/e3sm_scratch/files_map - topo_root=${SCRATCH}/e3sm_scratch/files_topo - DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata - NE=30 - ``` - Example settings for Chrysalis (ANL/LCRC): - ```shell - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - NE=30 - ``` - Make sure the directories exist: - ``` - mkdir -p ${grid_root} ${map_root} ${topo_root} - ``` + ```shell + e3sm_root= + grid_root= + map_root= + topo_root= + DIN_LOC_ROOT= + NE= + ``` + Example settings for Perlmutter (NERSC): + ```shell + grid_root=${SCRATCH}/e3sm_scratch/files_grid + map_root=${SCRATCH}/e3sm_scratch/files_map + topo_root=${SCRATCH}/e3sm_scratch/files_topo + DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata + NE=30 + ``` + Example settings for Chrysalis (ANL/LCRC): + ```shell + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + NE=30 + ``` + Make sure the directories exist: + ``` + mkdir -p ${grid_root} ${map_root} ${topo_root} + ``` 1. **Specify all topo and map file paths for consistency** - ```shell - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc - map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc - map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc - map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc - ``` + ```shell + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc + map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc + map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc + map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc + ``` 1. **Create grid and map files** - 1. source the unified env - - Perlmutter (NERSC): - ```shell - source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh - ``` - Chrysalis (ANL/LCRC): - ```shell - source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh - ``` - - 1. Create grid files for the input high res topo - ```shell - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc - ``` - - 1. Create grid files target EAM grid - ```shell - GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc - ``` - - 1. Create map files - - !!!WARNING - this can take a long time - 1. from source to target np4 - ```shell - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} - ``` - 1. from source to target pg2 - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} - ``` - 1. from target to source (needed for calculating sub-grid anomalies on target grid) - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} - ``` - -1. **Create new topograpy data on target grid** - - 1. Map high-res topo to target np4 grid - ```shell - ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - ``` - - 1. Compute phi_s on the np4 grid - ```shell - ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - ``` - -1. **Use homme_tool to smooth topography** - - 1. Set the machine specific environment - ```shell - cd ${e3sm_root}/components/homme - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ``` - - 1. Build homme_tool - - The build process requires the user to select the appropriate cmake file that contains machine-specific settings. - ```shell - mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake - - cmake -C ${mach_file} \ - -DBUILD_HOMME_THETA_KOKKOS=FALSE \ - -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ - -DHOMME_ENABLE_COMPOSE=FALSE \ - -DHOMME_BUILD_EXECS=FALSE \ - -DBUILD_HOMME_TOOL=TRUE \ - -DPREQX_PLEV=26 \ - ${e3sm_root}/components/homme - - make -j4 homme_tool - ``` - - 1. run homme_tool - ```shell - cat < input.nl - &ctl_nl - ne = ${NE} - mesh_file = "${grid_root}/exodus_ne${NE}.g" - smooth_phis_p2filt = 0 - smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing - smooth_phis_nudt = 4e-16 - hypervis_scaling = 2 - se_ftype = 2 ! actually output NPHYS; overloaded use of ftype - / - &vert_nl - / - &analysis_nl - tool = 'topo_pgn_to_smoothed' - infilenames = '${topo_file_2}', '${topo_file_3::-3}' - / - EOF - - mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - ``` - -1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** + 1. source the unified env - 1. Remap smoothed topo to ne3000 grid - ```shell - ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} - ``` - - 1. Append unsmoothed ne3000 data + Perlmutter (NERSC): ```shell - ncks -A ${topo_file_0} ${topo_file_4} + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh ``` - - 1. Calculate anomalies on ne3000 grid - - (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) - ```shell - ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} - ``` - - 1. Remap anomalies back to target pg2 grid - ```shell - ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - ``` - - -1. **???? Append LANDFRAC and LANDM_COSLAT ????** - -1. **Append the GLL phi_s data to the output of step 4** + Chrysalis (ANL/LCRC): ```shell - TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp - TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc - ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} + source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh ``` -## Batch scripts to streamline all steps - -Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). - -To submit the slurm batch job use `sbatch batch_topo_slurm.sh` - -
- batch_topo_slurm.sh + 1. Create grid files for the input high res topo ```shell - #!/bin/bash - #SBATCH --constraint=cpu - #SBATCH --account=m3312 - #SBATCH -q regular - #SBATCH --job-name=generate_map - #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out - #SBATCH --time=24:00:00 - #SBATCH --nodes=1 - #SBATCH --mail-user=hannah6@llnl.gov - #SBATCH --mail-type=END,FAIL - - e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - - NE=30 - - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - - source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh - - # Create grid files for the input high res topo GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + ``` - # Create grid files target EAM grid + 1. Create grid files target EAM grid + ```shell GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + ``` - # Create map file - source to target - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc + 1. Create map files + + !!!WARNING + this can take a long time + 1. from source to target np4 + ```shell + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} + ``` + 1. from source to target pg2 + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} + ``` + 1. from target to source (needed for calculating sub-grid anomalies on target grid) + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} + ``` - # Create map file - target to source - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc +1. **Create new topograpy data on target grid** - # Map high-res topo to target np4 grid + 1. Map high-res topo to target np4 grid + ```shell ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} + ``` - # Compute phi_s on the np4 grid + 1. Compute phi_s on the np4 grid + ```shell ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + ``` + +1. **Use homme_tool to smooth topography** + + 1. Set the machine specific environment + ```shell + cd ${e3sm_root}/components/homme + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ``` + + 1. Build homme_tool + + The build process requires the user to select the appropriate cmake file that contains machine-specific settings. + ```shell + mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake + + cmake -C ${mach_file} \ + -DBUILD_HOMME_THETA_KOKKOS=FALSE \ + -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ + -DHOMME_ENABLE_COMPOSE=FALSE \ + -DHOMME_BUILD_EXECS=FALSE \ + -DBUILD_HOMME_TOOL=TRUE \ + -DPREQX_PLEV=26 \ + ${e3sm_root}/components/homme + + make -j4 homme_tool + ``` - # Use homme_tool to smooth topography + 1. run homme_tool + ```shell cat < input.nl &ctl_nl ne = ${NE} @@ -292,13 +178,127 @@ To submit the slurm batch job use `sbatch batch_topo_slurm.sh` EOF mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl + ``` - # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data +1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** + + 1. Remap smoothed topo to ne3000 grid + ```shell ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} - ncks -A ${topo_file_0} ${topo_file_4} + ``` + + 1. Append unsmoothed ne3000 data + ```shell + ncks -A ${topo_file_0} ${topo_file_4} + ``` + + 1. Calculate anomalies on ne3000 grid + + (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) + ```shell ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} - ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - + ``` + 1. Remap anomalies back to target pg2 grid + ```shell + ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} ``` + + +1. **???? Append LANDFRAC and LANDM_COSLAT ????** + +1. **Append the GLL phi_s data to the output of step 4** + ```shell + TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp + TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc + ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} + ``` + +## Batch scripts to streamline all steps + +Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). + +To submit the slurm batch job use `sbatch batch_topo_slurm.sh` + +
+ batch_topo_slurm.sh + ```shell + #!/bin/bash + #SBATCH --constraint=cpu + #SBATCH --account=m3312 + #SBATCH -q regular + #SBATCH --job-name=generate_map + #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out + #SBATCH --time=24:00:00 + #SBATCH --nodes=1 + #SBATCH --mail-user=hannah6@llnl.gov + #SBATCH --mail-type=END,FAIL + + e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + + NE=30 + + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + + # Create grid files for the input high res topo + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + + # Create grid files target EAM grid + GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + + # Create map file - source to target + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc + + # Create map file - target to source + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc + + # Map high-res topo to target np4 grid + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} + + # Compute phi_s on the np4 grid + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + + # Use homme_tool to smooth topography + cat < input.nl + &ctl_nl + ne = ${NE} + mesh_file = "${grid_root}/exodus_ne${NE}.g" + smooth_phis_p2filt = 0 + smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing + smooth_phis_nudt = 4e-16 + hypervis_scaling = 2 + se_ftype = 2 ! actually output NPHYS; overloaded use of ftype + / + &vert_nl + / + &analysis_nl + tool = 'topo_pgn_to_smoothed' + infilenames = '${topo_file_2}', '${topo_file_3::-3}' + / + EOF + + mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl + + # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data + ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + ncks -A ${topo_file_0} ${topo_file_4} + ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} + ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} + + + ```
From cde2480f1890f9aa535517183277beb9999066ac Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 17 May 2024 16:07:09 -0600 Subject: [PATCH 177/388] formatting adjustments --- .../generate-topo-file.md | 473 +++++++++--------- 1 file changed, 250 insertions(+), 223 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index e3f58ad405a..9d67c7d830f 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -16,9 +16,9 @@ The workflow to generate topography data for the atmosphere model must address t - The dycore needs surface geopotential (`phi_s`) at GLL nodes (np4) - The physics needs various things at FV cell centers (pg2) - - surface geopotential (`phi_s`) - - sub-grid variance of topography (`SGH` and `SGH30`) - - Land area fraction (`LANDFRAC`) + - surface geopotential (`phi_s`) + - sub-grid variance of topography (`SGH` and `SGH30`) + - Land area fraction (`LANDFRAC`) - The np4 to pg2 map of `phi_s` data must be equal to the FV `phi_s` data - HOMME's smoothing operator must be used on `phi_s` for stability @@ -27,138 +27,279 @@ The workflow to generate topography data for the atmosphere model must address t Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. !!! NOTE - homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. + homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. ## Step-by-Step Topography Generation 1. **Set some helpful environmental variables used in commands below** - ```shell - e3sm_root= - grid_root= - map_root= - topo_root= - DIN_LOC_ROOT= - NE= - ``` - Example settings for Perlmutter (NERSC): - ```shell - grid_root=${SCRATCH}/e3sm_scratch/files_grid - map_root=${SCRATCH}/e3sm_scratch/files_map - topo_root=${SCRATCH}/e3sm_scratch/files_topo - DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata - NE=30 - ``` - Example settings for Chrysalis (ANL/LCRC): - ```shell - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - NE=30 - ``` - Make sure the directories exist: - ``` - mkdir -p ${grid_root} ${map_root} ${topo_root} - ``` -1. **Specify all topo and map file paths for consistency** - ```shell - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc - map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc - map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc - map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc - ``` + ```shell + e3sm_root= + grid_root= + map_root= + topo_root= + DIN_LOC_ROOT= + NE= + ``` -1. **Create grid and map files** + Example settings for Perlmutter (NERSC): - 1. source the unified env - - Perlmutter (NERSC): ```shell - source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + grid_root=${SCRATCH}/e3sm_scratch/files_grid + map_root=${SCRATCH}/e3sm_scratch/files_map + topo_root=${SCRATCH}/e3sm_scratch/files_topo + DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata + NE=30 ``` - Chrysalis (ANL/LCRC): + + Example settings for Chrysalis (ANL/LCRC): + ```shell - source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + NE=30 ``` - 1. Create grid files for the input high res topo + Make sure the directories exist: + ```shell - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + mkdir -p ${grid_root} ${map_root} ${topo_root} ``` - 1. Create grid files target EAM grid +1. **Specify all topo and map file paths for consistency** + ```shell - GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc - ``` + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc + map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc + map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc + map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc + ``` - 1. Create map files - - !!!WARNING - this can take a long time - 1. from source to target np4 - ```shell - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} - ``` - 1. from source to target pg2 - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} - ``` - 1. from target to source (needed for calculating sub-grid anomalies on target grid) - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} - ``` +1. **Create grid and map files** + + 1. source the unified env + + Perlmutter (NERSC): + + ```shell + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + ``` + + Chrysalis (ANL/LCRC): + + ```shell + source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh + ``` + + 1. Create grid files for the input high res topo + + ```shell + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + ``` + + 1. Create grid files target EAM grid + + ```shell + GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + ``` + + 1. Create map files + + !!!WARNING + this can take a long time + + 1. from source to target np4 + + ```shell + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} + ``` + + 1. from source to target pg2 + + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} + ``` + + 1. from target to source (needed for calculating sub-grid anomalies on target grid) + + ```shell + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} + ``` 1. **Create new topograpy data on target grid** - 1. Map high-res topo to target np4 grid - ```shell - ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - ``` + 1. Map high-res topo to target np4 grid - 1. Compute phi_s on the np4 grid - ```shell - ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - ``` + ```shell + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} + ``` + + 1. Compute phi_s on the np4 grid + + ```shell + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + ``` 1. **Use homme_tool to smooth topography** - 1. Set the machine specific environment - ```shell - cd ${e3sm_root}/components/homme - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ``` + 1. Set the machine specific environment + + ```shell + cd ${e3sm_root}/components/homme + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + ``` + + 1. Build homme_tool + + The build process requires the user to select the appropriate cmake file that contains machine-specific settings. + + ```shell + mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake + # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake + + cmake -C ${mach_file} \ + -DBUILD_HOMME_THETA_KOKKOS=FALSE \ + -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ + -DHOMME_ENABLE_COMPOSE=FALSE \ + -DHOMME_BUILD_EXECS=FALSE \ + -DBUILD_HOMME_TOOL=TRUE \ + -DPREQX_PLEV=26 \ + ${e3sm_root}/components/homme + + make -j4 homme_tool + ``` + + 1. run homme_tool + + ```shell + cat < input.nl + &ctl_nl + ne = ${NE} + mesh_file = "${grid_root}/exodus_ne${NE}.g" + smooth_phis_p2filt = 0 + smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing + smooth_phis_nudt = 4e-16 + hypervis_scaling = 2 + se_ftype = 2 ! actually output NPHYS; overloaded use of ftype + / + &vert_nl + / + &analysis_nl + tool = 'topo_pgn_to_smoothed' + infilenames = '${topo_file_2}', '${topo_file_3::-3}' + / + EOF + + mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl + ``` - 1. Build homme_tool +1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** - The build process requires the user to select the appropriate cmake file that contains machine-specific settings. + 1. Remap smoothed topo to ne3000 grid + ```shell + ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + ``` + + 1. Append unsmoothed ne3000 data + ```shell + ncks -A ${topo_file_0} ${topo_file_4} + ``` + + 1. Calculate anomalies on ne3000 grid + + (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) + + ```shell + ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} + ``` + + 1. Remap anomalies back to target pg2 grid + + ```shell + ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} + ``` + + +1. **???? Append LANDFRAC and LANDM_COSLAT ????** + +1. **Append the GLL phi_s data to the output of step 4** + ```shell - mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake - - cmake -C ${mach_file} \ - -DBUILD_HOMME_THETA_KOKKOS=FALSE \ - -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ - -DHOMME_ENABLE_COMPOSE=FALSE \ - -DHOMME_BUILD_EXECS=FALSE \ - -DBUILD_HOMME_TOOL=TRUE \ - -DPREQX_PLEV=26 \ - ${e3sm_root}/components/homme - - make -j4 homme_tool + TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp + TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc + ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} ``` - 1. run homme_tool +## Batch scripts to streamline all steps + +Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). + +To submit the slurm batch job use `sbatch batch_topo_slurm.sh` + +
+ batch_topo_slurm.sh ```shell + #!/bin/bash + #SBATCH --constraint=cpu + #SBATCH --account=m3312 + #SBATCH -q regular + #SBATCH --job-name=generate_map + #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out + #SBATCH --time=24:00:00 + #SBATCH --nodes=1 + #SBATCH --mail-user=hannah6@llnl.gov + #SBATCH --mail-type=END,FAIL + + e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone + grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid + map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map + topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + + NE=30 + + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc + + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + + # Create grid files for the input high res topo + GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc + + # Create grid files target EAM grid + GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + + # Create map file - source to target + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc + + # Create map file - target to source + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc + + # Map high-res topo to target np4 grid + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} + + # Compute phi_s on the np4 grid + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + + # Use homme_tool to smooth topography cat < input.nl &ctl_nl ne = ${NE} @@ -178,127 +319,13 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en EOF mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - ``` -1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** - - 1. Remap smoothed topo to ne3000 grid - ```shell + # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} - ``` - - 1. Append unsmoothed ne3000 data - ```shell - ncks -A ${topo_file_0} ${topo_file_4} - ``` - - 1. Calculate anomalies on ne3000 grid - - (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) - ```shell + ncks -A ${topo_file_0} ${topo_file_4} ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} - ``` - - 1. Remap anomalies back to target pg2 grid - ```shell ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - ``` - - -1. **???? Append LANDFRAC and LANDM_COSLAT ????** - -1. **Append the GLL phi_s data to the output of step 4** - ```shell - TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp - TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc - ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} - ``` - -## Batch scripts to streamline all steps - -Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). - -To submit the slurm batch job use `sbatch batch_topo_slurm.sh` + -
- batch_topo_slurm.sh - ```shell - #!/bin/bash - #SBATCH --constraint=cpu - #SBATCH --account=m3312 - #SBATCH -q regular - #SBATCH --job-name=generate_map - #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out - #SBATCH --time=24:00:00 - #SBATCH --nodes=1 - #SBATCH --mail-user=hannah6@llnl.gov - #SBATCH --mail-type=END,FAIL - - e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - - NE=30 - - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - - source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh - - # Create grid files for the input high res topo - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc - - # Create grid files target EAM grid - GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc - - # Create map file - source to target - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc - - # Create map file - target to source - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc - - # Map high-res topo to target np4 grid - ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - - # Compute phi_s on the np4 grid - ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - - # Use homme_tool to smooth topography - cat < input.nl - &ctl_nl - ne = ${NE} - mesh_file = "${grid_root}/exodus_ne${NE}.g" - smooth_phis_p2filt = 0 - smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing - smooth_phis_nudt = 4e-16 - hypervis_scaling = 2 - se_ftype = 2 ! actually output NPHYS; overloaded use of ftype - / - &vert_nl - / - &analysis_nl - tool = 'topo_pgn_to_smoothed' - infilenames = '${topo_file_2}', '${topo_file_3::-3}' - / - EOF - - mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - - # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data - ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} - ncks -A ${topo_file_0} ${topo_file_4} - ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} - ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - - - ``` + ```
From e4c4f61c89c9e8bfc90bce395d7b2fea57c4ec10 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 17 May 2024 16:12:50 -0600 Subject: [PATCH 178/388] linter fixes --- .../generate-topo-file.md | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index 9d67c7d830f..c6b2e5b823f 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -24,11 +24,15 @@ The workflow to generate topography data for the atmosphere model must address t ## Topography Smoothing -Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. +Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. !!! NOTE homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. + + + + ## Step-by-Step Topography Generation 1. **Set some helpful environmental variables used in commands below** @@ -51,7 +55,7 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata NE=30 ``` - + Example settings for Chrysalis (ANL/LCRC): ```shell @@ -81,12 +85,12 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc - ``` + ``` 1. **Create grid and map files** 1. source the unified env - + Perlmutter (NERSC): ```shell @@ -115,7 +119,7 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en ``` 1. Create map files - + !!!WARNING this can take a long time @@ -161,7 +165,7 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en ``` 1. Build homme_tool - + The build process requires the user to select the appropriate cmake file that contains machine-specific settings. ```shell @@ -205,13 +209,15 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en ``` 1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** - + 1. Remap smoothed topo to ne3000 grid + ```shell ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} ``` 1. Append unsmoothed ne3000 data + ```shell ncks -A ${topo_file_0} ${topo_file_4} ``` @@ -225,12 +231,11 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en ``` 1. Remap anomalies back to target pg2 grid - + ```shell ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} ``` - 1. **???? Append LANDFRAC and LANDM_COSLAT ????** 1. **Append the GLL phi_s data to the output of step 4** @@ -260,7 +265,7 @@ To submit the slurm batch job use `sbatch batch_topo_slurm.sh` #SBATCH --nodes=1 #SBATCH --mail-user=hannah6@llnl.gov #SBATCH --mail-type=END,FAIL - + e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map @@ -326,6 +331,5 @@ To submit the slurm batch job use `sbatch batch_topo_slurm.sh` ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - ```
From 72fe8237ca542f11f122eb5bf49e0890ed38e363 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 20 May 2024 17:07:43 -0600 Subject: [PATCH 179/388] major topo workflow updates - still needs some work though --- .../generate-topo-file.md | 323 ++++++++++-------- 1 file changed, 189 insertions(+), 134 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index c6b2e5b823f..42cc7b9a089 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -10,6 +10,8 @@ Traditionally the topography generation for E3SM start with **USGS-topo-cube3000 For target resolutions of 3 km or finer it is recommended to use **USGS-topo-cube12000.nc**, which was created by Jishi Zhang in 2024. This file has a resolution of 750m created from a 500m/250m USGS GMTED2010 source DEM dataset (see [here](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/4189520033/800m+cubed+topo+generation+from+GMTED2010+15s+DEM) for more information). +For testing the topography workflow the mapping between the ne3000 data is much too burdensome, so a ne90pg1 (i.e. 1-degree) version of this data was created to allow efficient testing. This file can be found in the inputdata repository at `${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube90.nc`. + ## Data Processing Requirements The workflow to generate topography data for the atmosphere model must address the following requirements: @@ -43,27 +45,26 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en map_root= topo_root= DIN_LOC_ROOT= - NE= + NE_SRC= + NE_DST= ``` - Example settings for Perlmutter (NERSC): + Example path settings for Perlmutter (NERSC): ```shell grid_root=${SCRATCH}/e3sm_scratch/files_grid map_root=${SCRATCH}/e3sm_scratch/files_map topo_root=${SCRATCH}/e3sm_scratch/files_topo DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata - NE=30 ``` - Example settings for Chrysalis (ANL/LCRC): + Example path settings for Chrysalis (ANL/LCRC): ```shell grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - NE=30 ``` Make sure the directories exist: @@ -75,16 +76,31 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en 1. **Specify all topo and map file paths for consistency** ```shell - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - topo_file_6=${topo_root}/USGS-topo_ne${NE}np4_smoothed_anomalies.nc - map_file_src_to_np4=${map_root}/map_ne3000pg1_to_ne${NE}np4_fv2se_flx.nc - map_file_src_to_pg2=${map_root}/map_ne3000pg1_to_ne${NE}pg2_traave.nc - map_file_pg2_to_src=${map_root}/map_ne${NE}pg2_to_ne3000pg1_traave.nc + # topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc + # topo_file_1=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4.nc + # topo_file_2=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_phis.nc + # topo_file_3=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t.nc + # topo_file_4=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1.nc + # topo_file_5=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1_anomalies.nc + # topo_file_6=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_anomalies.nc + # topo_file_7=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_sgh.nc + # topo_file_8=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothedx6t.nc + + + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc + topo_file_1=${topo_root}/USGS-topo_tmp_ne${NE_SRC}pg1.nc + topo_file_2=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4.nc + topo_file_3=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t.nc + topo_file_4=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1.nc + topo_file_5=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1_anomalies.nc + topo_file_6=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_anomalies.nc + topo_file_7=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_sgh.nc + topo_file_8=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothedx6t.nc + + map_file_src_to_np4=${map_root}/map_ne${NE_SRC}pg1_to_ne${NE_DST}np4_fv2se_flx.nc + map_file_src_to_pg2=${map_root}/map_ne${NE_SRC}pg1_to_ne${NE_DST}pg2_traave.nc + map_file_pg2_to_src=${map_root}/map_ne${NE_DST}pg2_to_ne${NE_SRC}pg1_traave.nc + map_file_np4_to_pg2=${map_root}/map_ne${NE_DST}np4_to_ne${NE_DST}pg2_se2fv_flx.nc ``` 1. **Create grid and map files** @@ -103,72 +119,73 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh ``` - 1. Create grid files for the input high res topo - - ```shell - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc - ``` - - 1. Create grid files target EAM grid + 1. Create grid files ```shell - GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc + # Grid for source high res topo + GenerateCSMesh --alt --res ${NE_SRC} --file ${grid_root}/exodus_ne${NE_SRC}.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_SRC}.g --out ${grid_root}/scrip_ne${NE_SRC}pg1.nc + + # Grid for target EAM grid + GenerateCSMesh --alt --res ${NE_DST} --file ${grid_root}/exodus_ne${NE_DST}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE_DST}.g --out ${grid_root}/exodus_ne${NE_DST}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_DST}pg2.g --out ${grid_root}/scrip_ne${NE_DST}pg2.nc ``` 1. Create map files !!!WARNING - this can take a long time - - 1. from source to target np4 - - ```shell - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_np4} - ``` - - 1. from source to target pg2 - - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_file_src_to_pg2} - ``` - - 1. from target to source (needed for calculating sub-grid anomalies on target grid) + This can take a long time - several hours for each map file in some cases - ```shell - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_file_pg2_to_src} - ``` + ```shell + # from source to target np4 + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/exodus_ne${NE_DST}.g --map_file=${map_file_src_to_np4} + + # from source to target pg2 + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --map_file=${map_file_src_to_pg2} + + # from target to source (needed for calculating sub-grid anomalies on target grid) + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --dst_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --map_file=${ + map_file_pg2_to_src} + + # from target np4 to target pg2 + ncremap -a se2fv_flx -5 --src_grd=${grid_root}/exodus_ne${NE_DST}.g --dst_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --map_file=${map_file_np4_to_pg2} + ``` 1. **Create new topograpy data on target grid** - 1. Map high-res topo to target np4 grid + ```shell + # # Map high-res topo to target np4 grid + # ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - ```shell - ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - ``` + # # Compute phi_s on the np4 grid + # ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - 1. Compute phi_s on the np4 grid + # # rename the column dimension to be "ncol" + # ncrename -d grid_size,ncol ${topo_file_2} - ```shell - ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - ``` + # Compute phi_s on the source np4 grid + ncap2 -s 'PHIS=terr*9.80616' ${topo_file_0} ${topo_file_1} -1. **Use homme_tool to smooth topography** + # rename the column dimension to be "ncol" + ncrename -d grid_size,ncol ${topo_file_1} - 1. Set the machine specific environment + # Map high-res topo to target np4 grid + ncremap -m ${map_file_src_to_np4} -i ${topo_file_1} -o ${topo_file_2} + ``` - ```shell - cd ${e3sm_root}/components/homme - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - ``` +1. **Use homme_tool to smooth topography** 1. Build homme_tool The build process requires the user to select the appropriate cmake file that contains machine-specific settings. ```shell + # Set the machine specific environment + cd ${e3sm_root}/components/homme + eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) + + # Specify machine configuration file mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake @@ -185,14 +202,14 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en ``` 1. run homme_tool - + + ```shell cat < input.nl &ctl_nl - ne = ${NE} - mesh_file = "${grid_root}/exodus_ne${NE}.g" + mesh_file = "${grid_root}/exodus_ne${NE_DST}.g" smooth_phis_p2filt = 0 - smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing + smooth_phis_numcycle = 6 ! v2/v3 uses 12/6 for more/less smoothing smooth_phis_nudt = 4e-16 hypervis_scaling = 2 se_ftype = 2 ! actually output NPHYS; overloaded use of ftype @@ -201,114 +218,151 @@ Smoothing of the input surface geopotential (`phi_s`) is an essential step to en / &analysis_nl tool = 'topo_pgn_to_smoothed' - infilenames = '${topo_file_2}', '${topo_file_3::-3}' + infilenames = '${topo_file_2}', '${topo_file_3}' / EOF mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - ``` -1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** - - 1. Remap smoothed topo to ne3000 grid - - ```shell - ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + # rename output file to remove "1.nc" suffix + mv ${topo_file_3}1.nc ${topo_file_3} ``` - 1. Append unsmoothed ne3000 data +1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** - ```shell - ncks -A ${topo_file_0} ${topo_file_4} - ``` + ```shell + # Remap smoothed data back to source grid + ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} + + # Calculate anomalies on source grid + ncdiff -O ${topo_file_1} ${topo_file_4} ${topo_file_5} + + # Square the anomaly values + ncap2 -O -s 'PHIS_ANOM_SQ=PHIS^2' ${topo_file_5} ${topo_file_5} + + # Remap squared anomalies back to target pg2 grid + ncremap -v PHIS_ANOM_SQ -m ${map_file_src_to_pg2} -i ${topo_file_5} -o ${topo_file_6} + + # Take the square root of the remapped to get standard deviation (SGH) + ncap2 -O -s 'SGH=sqrt(PHIS_ANOM_SQ)' ${topo_file_6} ${topo_file_7} + ``` - 1. Calculate anomalies on ne3000 grid +1. **Put all quantities into the final topo file** - (Note that for ncdiff the operation is `file_3 = file_1 - file_2`) + ```shell + + # Create final topo file starting with smoothed PHIS data + cp ${topo_file_3} ${topo_file_8} - ```shell - ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} - ``` + # Append the SGH data + ncks -A -v SGH ${topo_file_7} ${topo_file_8} - 1. Remap anomalies back to target pg2 grid + # rename GLL coordinate to ncol_g + ncrename -d ncol,ncol_d ${topo_file_2} - ```shell - ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - ``` + # Map np4 LANDFRAC and SGH30 to the target pg2 grid + ncremap -v SGH30,LANDFRAC -m ${map_file_np4_to_pg2} -i ${topo_file_2} -o ${????} -1. **???? Append LANDFRAC and LANDM_COSLAT ????** + # Append the pg2 LANDFRAC and SGH30 data to final file + ncks -A -v SGH30,LANDFRAC --hdr_pad=100000 ${?????} ${topo_file_8} + + ``` -1. **Append the GLL phi_s data to the output of step 4** +1. **Clean up temporary files** ```shell - TOPO_FILE_2=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_phis_x6t_tmp - TOPO_FILE_3=${DATA_FILE_ROOT}/USGS-topo_ne${NE}np4_smoothed_x6tensor.nc - ncks -A ${TOPO_FILE_2}1.nc ${TOPO_FILE_3} + rm ${topo_root}/USGS-topo_tmp_* ``` -## Batch scripts to streamline all steps +## Batch script to streamline all steps + +Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. + +Here's a check list of things to do before submitting this script: -Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. Also, be sure to comment out any parts that have already been completed in advance (like creating the grid files). +- Build `homme_tool` +- Update allocation code (i.e. `--account` +- Update batch job wallclock time +- Update paths at the top of the batch script +- Comment out any sections that were completed in advance (i.e. grid file creation) To submit the slurm batch job use `sbatch batch_topo_slurm.sh` -
+
batch_topo_slurm.sh ```shell #!/bin/bash + #SBATCH --account=### PUT ALLOCATION CODE HERE ### #SBATCH --constraint=cpu - #SBATCH --account=m3312 - #SBATCH -q regular - #SBATCH --job-name=generate_map - #SBATCH --output=~/E3SM/logs_slurm/slurm-%x-%j.out + #SBATCH --qos=regular + #SBATCH --job-name=generate_topo + #SBATCH --output=slurm-%x-%j.out #SBATCH --time=24:00:00 #SBATCH --nodes=1 - #SBATCH --mail-user=hannah6@llnl.gov - #SBATCH --mail-type=END,FAIL - - e3sm_root=/pscratch/sd/w/whannah/e3sm_scratch/tmp_clone - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata - - NE=30 - - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube3000.nc - topo_file_1=${topo_root}/USGS-topo_ne${NE}np4.nc - topo_file_2=${topo_root}/USGS-topo_ne${NE}np4_phis.nc - topo_file_3=${topo_root}/USGS-topo_ne${NE}np4_smoothed.nc - topo_file_4=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1.nc - topo_file_5=${topo_root}/USGS-topo_ne${NE}np4_smoothed_ne3000pg1_anomalies.nc - + #--------------------------------------------------------------------------- + # Stop execution on any error + set -e + #--------------------------------------------------------------------------- + e3sm_root= + grid_root= + map_root= + topo_root= + DIN_LOC_ROOT= + NE_SRC= + NE_DST= + #--------------------------------------------------------------------------- + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc + topo_file_1=${topo_root}/USGS-topo_ne${NE_DST}np4.nc + topo_file_2=${topo_root}/USGS-topo_ne${NE_DST}np4_phis.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothed.nc + topo_file_4=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothed_ne${NE_SRC}pg1.nc + topo_file_5=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothed_ne${NE_SRC}pg1_anomalies.nc + topo_file_6=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothed_anomalies.nc + #--------------------------------------------------------------------------- + # print some useful things to the log file + echo e3sm_root = $e3sm_root + echo grid_root = $grid_root + echo map_root = $map_root + echo topo_root = $topo_root + echo DIN_LOC_ROOT = $DIN_LOC_ROOT + echo topo_file_0 = $topo_file_0 + echo topo_file_1 = $topo_file_1 + echo topo_file_2 = $topo_file_2 + echo topo_file_3 = $topo_file_3 + echo topo_file_4 = $topo_file_4 + echo topo_file_5 = $topo_file_5 + echo topo_file_6 = $topo_file_6 + #--------------------------------------------------------------------------- source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh - + #--------------------------------------------------------------------------- # Create grid files for the input high res topo - GenerateCSMesh --alt --res 3000 --file ${grid_root}/exodus_ne3000.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne3000.g --out ${grid_root}/scrip_ne3000pg1.nc - + GenerateCSMesh --alt --res ${NE_SRC} --file ${grid_root}/exodus_ne${NE_SRC}.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_SRC}.g --out ${grid_root}/scrip_ne${NE_SRC}pg1.nc + #--------------------------------------------------------------------------- # Create grid files target EAM grid - GenerateCSMesh --alt --res ${NE} --file ${grid_root}/exodus_ne${NE}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE}.g --out ${grid_root}/exodus_ne${NE}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE}pg2.g --out ${grid_root}/scrip_ne${NE}pg2.nc - - # Create map file - source to target - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne3000pg1.nc --dst_grd=${grid_root}/exodus_ne${NE}.g --map_file=${map_root}/map_ne3000pg1_to_ne${NE}np4.nc - - # Create map file - target to source - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE}pg2.nc --dst_grd=${grid_root}/scrip_ne3000pg1.nc --map_file=${map_root}/map_ne${NE}pg2_to_ne3000pg1.nc - + GenerateCSMesh --alt --res ${NE_DST} --file ${grid_root}/exodus_ne${NE_DST}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE_DST}.g --out ${grid_root}/exodus_ne${NE_DST}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_DST}pg2.g --out ${grid_root}/scrip_ne${NE_DST}pg2.nc + #--------------------------------------------------------------------------- + # Create map files + # from source to target np4 + ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/exodus_ne${NE_DST}.g --map_file=${map_file_src_to_np4} + # from source to target pg2 + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --map_file=${map_file_src_to_pg2} + # from target to source (needed for calculating sub-grid anomalies on target grid) + ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --dst_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --map_file=${map_file_pg2_to_src} + #--------------------------------------------------------------------------- # Map high-res topo to target np4 grid ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - + #--------------------------------------------------------------------------- # Compute phi_s on the np4 grid ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} - + #--------------------------------------------------------------------------- # Use homme_tool to smooth topography cat < input.nl &ctl_nl - ne = ${NE} - mesh_file = "${grid_root}/exodus_ne${NE}.g" + ne = ${NE_DST} + mesh_file = "${grid_root}/exodus_ne${NE_DST}.g" smooth_phis_p2filt = 0 smooth_phis_numcycle = 12 # v3 uses 6 for less smoothing smooth_phis_nudt = 4e-16 @@ -322,14 +376,15 @@ To submit the slurm batch job use `sbatch batch_topo_slurm.sh` infilenames = '${topo_file_2}', '${topo_file_3::-3}' / EOF - mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - + #--------------------------------------------------------------------------- # Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} ncks -A ${topo_file_0} ${topo_file_4} ncdiff ${topo_file_0} ${topo_file_4} ${topo_file_5} ncremap -m ${map_file_src_to_pg2} -i ${topo_file_0} -o ${topo_file_6} - + #--------------------------------------------------------------------------- + #--------------------------------------------------------------------------- + #--------------------------------------------------------------------------- ```
From f19abfaad983ec3d21a259f659aff44b2f831d67 Mon Sep 17 00:00:00 2001 From: Chloe Date: Tue, 21 May 2024 13:01:32 -0700 Subject: [PATCH 180/388] remove inncorrectly placed line in elm_instMod.F90 for use_extrasnowlayers --- components/elm/src/main/elm_instMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/components/elm/src/main/elm_instMod.F90 b/components/elm/src/main/elm_instMod.F90 index b8afca87e24..90b576c320d 100644 --- a/components/elm/src/main/elm_instMod.F90 +++ b/components/elm/src/main/elm_instMod.F90 @@ -352,7 +352,6 @@ subroutine elm_inst_biogeophys(bounds_proc) snow_depth_col(c) = h2osno_col(c) / bdsno endif endif - snow_depth_col(c) = h2osno_col(c) / bdsno end do ! Initialize urban constants From cb0a3d38fe3ecda018af9c276af85ae3e7c4f518 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Tue, 21 May 2024 20:37:47 -0700 Subject: [PATCH 181/388] Fixes the ELM's SPBC compset Removes turning on of the subgrid solar topographic radiation scheme. [BFB] --- components/elm/cime_config/config_component.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/cime_config/config_component.xml b/components/elm/cime_config/config_component.xml index 94fac9ab939..f18b1cb4a01 100755 --- a/components/elm/cime_config/config_component.xml +++ b/components/elm/cime_config/config_component.xml @@ -114,7 +114,7 @@ -bgc sp -solar_rad_scheme top -bgc sp - -bgc sp -solar_rad_scheme top + -bgc sp -bgc cn -bgc bgc -bgc cn -crop From 4d9c01bb8483c053fa9bdd9fc7817872a65087f6 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Thu, 8 Jun 2023 11:15:55 -0600 Subject: [PATCH 182/388] Add iceThicknessHydro to replace thickness thickness field is replaced by iceThicknessHydro, which makes changes along the boundaries where the surface evelation of a boundary cell is a local minimum. In this case the surface elevation of that cell is replaced by the minimum of its non-boundary neighbors, and the ice thickness is then recalculated from the updated surface elevation. The intent of this commit is to inhibit the formation of subglacial lakes forming on the domain boundaries, which causes instabilities in the channel model. Physically, lakes should not form at the boundary as it is intended to be a high in hydropotential (a watershed boundary). --- .../src/Registry_subglacial_hydro.xml | 4 +- .../mode_forward/mpas_li_subglacial_hydro.F | 116 ++++++++++++++++-- .../src/shared/mpas_li_mask.F | 66 +++++++++- 3 files changed, 174 insertions(+), 12 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 083c92bcfbe..2fae65a0de1 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -140,7 +140,9 @@ - + diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 60cd6e5ca79..53e2edc9ee9 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -106,6 +106,7 @@ subroutine li_SGH_init(domain, err) real (kind=RKIND), dimension(:), pointer :: waterPressure real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: bedTopography + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro integer, dimension(:), pointer :: cellMask real (kind=RKIND), pointer :: tillMax real (kind=RKIND), pointer :: rhoi, rhoo @@ -182,8 +183,12 @@ subroutine li_SGH_init(domain, err) call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) call mpas_pool_get_array(geometryPool, 'thickness', thickness) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) + call calc_iceThicknessHydro(block, err_tmp) !adjust ice thickness along boundaries + err = ior(err,err_tmp) + waterPressure = max(0.0_RKIND, waterPressure) - waterPressure = min(waterPressure, rhoi * gravity * thickness) + waterPressure = min(waterPressure, rhoi * gravity * iceThicknessHydro) ! set pressure correctly under floating ice and open ocean call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) @@ -325,6 +330,9 @@ subroutine li_SGH_solve(domain, err) call mpas_pool_get_array(velocityPool, 'flowParamA', flowParamA) call mpas_pool_get_array(geometryPool, 'thickness', thickness) + call calc_iceThicknessHydro(block, err_tmp) + err = ior(err, err_tmp) + call li_calculate_flowParamA(meshPool, temperature, thickness, flowParamA, err_tmp) err = ior(err, err_tmp) @@ -1480,6 +1488,7 @@ subroutine calc_pressure(block, err) real (kind=RKIND), dimension(:), pointer :: divergenceChannel real (kind=RKIND), dimension(:), pointer :: channelAreaChangeCell real (kind=RKIND), dimension(:), pointer :: bedTopography + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:), pointer :: cellMask integer, dimension(:), pointer :: nEdgesOnCell @@ -1546,6 +1555,7 @@ subroutine calc_pressure(block, err) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) openingRate(:) = bedRough * basalSpeed(:) * (bedRoughMax - waterThickness(:)) !openingRate(:) = bedRough * basalSpeed(:) * (bedRoughMax - waterThickness(:)) + & @@ -1566,7 +1576,7 @@ subroutine calc_pressure(block, err) case ('cavity') where (li_mask_is_floating_ice(cellMask)) - waterPressure = rhoi * gravity * thickness + waterPressure = rhoi * gravity * iceThicknessHydro elsewhere (.not. li_mask_is_ice(cellMask)) waterPressure = 0.0_RKIND elsewhere @@ -1576,11 +1586,11 @@ subroutine calc_pressure(block, err) case ('overburden') where (li_mask_is_floating_ice(cellMask)) - waterPressure = rhoi * gravity * thickness + waterPressure = rhoi * gravity * iceThicknessHydro elsewhere (.not. li_mask_is_ice(cellMask)) waterPressure = 0.0_RKIND elsewhere - waterPressure = rhoi * gravity * thickness + waterPressure = rhoi * gravity * iceThicknessHydro end where case default @@ -1589,7 +1599,7 @@ subroutine calc_pressure(block, err) end select waterPressure = max(0.0_RKIND, waterPressure) - waterPressure = min(waterPressure, rhoi * gravity * thickness) + waterPressure = min(waterPressure, rhoi * gravity * iceThicknessHydro) do iCell = 1, nCells if ( li_mask_is_floating_ice(cellMask(iCell)) .or. & @@ -1638,7 +1648,6 @@ subroutine calc_pressure_diag_vars(block, err) !----------------------------------------------------------------- ! input variables !----------------------------------------------------------------- - !----------------------------------------------------------------- ! input/output variables !----------------------------------------------------------------- @@ -1663,6 +1672,7 @@ subroutine calc_pressure_diag_vars(block, err) real (kind=RKIND), dimension(:), pointer :: waterThickness real (kind=RKIND), dimension(:), pointer :: hydropotential real (kind=RKIND), dimension(:), pointer :: effectivePressure + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro integer, dimension(:), pointer :: cellMask real (kind=RKIND), pointer :: config_sea_level @@ -1683,9 +1693,10 @@ subroutine calc_pressure_diag_vars(block, err) call mpas_pool_get_array(hydroPool, 'hydropotentialBase', hydropotentialBase) call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) call mpas_pool_get_array(hydroPool, 'hydropotential', hydropotential) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) - effectivePressure = rhoi * gravity * thickness - waterPressure + effectivePressure = rhoi * gravity * iceThicknessHydro - waterPressure ! < this should evalute to 0 for floating ice if Pw set correctly there. where (.not. li_mask_is_grounded_ice(cellmask)) effectivePressure = 0.0_RKIND ! zero effective pressure where no ice to avoid confusion @@ -2161,6 +2172,7 @@ subroutine ocean_connection_N(domain) real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: effectivePressure + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro real (kind=RKIND), pointer :: rhoi, rhoo ! Calculate N assuming perfect ocean connection @@ -2175,7 +2187,9 @@ subroutine ocean_connection_N(domain) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure) - effectivePressure = rhoi * gravity * thickness - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) + + effectivePressure = rhoi * gravity * iceThicknessHydro - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography) effectivePressure = max(effectivePressure, 0.0_RKIND) ! This is just to zero out N in the open ocean to avoid confusion block => block % next @@ -2303,6 +2317,92 @@ subroutine calc_hydro_mask(domain) !-------------------------------------------------------------------- end subroutine calc_hydro_mask + + +!*********************************************************************** +! +! routine calc_iceThicknessHydro +! +!> \brief Calculate version of ice thickness used by hydrology model +!> \author Alex Hager +!> \date 7 June 2023 +!> \details +!> This routine calculates a modified ice thickness that is altered at +! the domain boundaries to avoid local minima in hydropotential +!----------------------------------------------------------------------- + subroutine calc_iceThicknessHydro(block, err) + + !----------------------------------------------------------------- + ! input variables + !----------------------------------------------------------------- + + !----------------------------------------------------------------- + ! input/output variables + !----------------------------------------------------------------- + type (block_type), intent(inout) :: block !< Input/Output: block object + + !----------------------------------------------------------------- + ! output variables + !----------------------------------------------------------------- + integer, intent(out) :: err !< Output: error flag + + !----------------------------------------------------------------- + ! local variables + !----------------------------------------------------------------- + ! Pools pointers + type (mpas_pool_type), pointer :: geometryPool + type (mpas_pool_type), pointer :: hydroPool + type (mpas_pool_type), pointer :: meshPool + real (kind=RKIND), dimension(:), pointer :: thickness + real (kind=RKIND), dimension(:), pointer :: bedTopography + real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro + real (kind=RKIND), dimension(:), pointer :: upperSurface + integer, dimension(:,:), pointer :: cellsOnCell + integer, dimension(:), pointer :: cellMask + integer, pointer :: nCells + integer :: iCell + integer :: jCell + real (kind=RKIND) :: minNeighborHeight + real (kind=RKIND), parameter :: bigValue = 1.0_RKIND + integer, dimension(:), pointer :: nEdgesOnCell + err = 0 + + ! Get pools things + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) + call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) + call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + + call mpas_pool_get_array(geometryPool, 'thickness', thickness) + call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) + call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) + call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface) + call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) + call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) + + iceThicknessHydro = thickness + + do iCell = 1, nCells + if ((li_mask_is_boundary(cellMask(iCell))) .and. (li_mask_is_grounded_ice(cellMask(iCell)))) then !identify domain boundaries + minNeighborHeight = bigValue !allocate + + do jCell = 1, nEdgesOnCell(iCell) + if ( .not. li_mask_is_boundary(cellMask(cellsOnCell(jCell,iCell)))) then + minNeighborHeight = min(minNeighborHeight, upperSurface(cellsOnCell(jCell,iCell))) + endif + end do + + !only adjust surface elevation if cell is local minimum + if ((upperSurface(iCell) < minNeighborHeight) .and. (minNeighborHeight < bigValue)) then + iceThicknessHydro(iCell) = minNeighborHeight - bedTopography(iCell) + endif + + endif + enddo + +!------------------------------------------------------------------------- + end subroutine calc_iceThicknessHydro !*********************************************************************** ! diff --git a/components/mpas-albany-landice/src/shared/mpas_li_mask.F b/components/mpas-albany-landice/src/shared/mpas_li_mask.F index 673ed8186e4..64050cb83ad 100644 --- a/components/mpas-albany-landice/src/shared/mpas_li_mask.F +++ b/components/mpas-albany-landice/src/shared/mpas_li_mask.F @@ -45,6 +45,7 @@ module li_mask integer, parameter :: li_mask_ValueAlbanyMarginNeighbor = 128 ! This the first cell beyond the last active albany cell integer, parameter :: li_mask_ValueGroundingLine = 256 !< This is grounded cell that has a floating neighbor, or vertex/edge on that boundary + integer, parameter :: li_mask_ValueDomainBoundary = 512 !-------------------------------------------------------------------- ! @@ -143,7 +144,18 @@ module li_mask module procedure li_mask_is_grounding_line_logout_0d end interface - !-------------------------------------------------------------------- + + interface li_mask_is_boundary + module procedure li_mask_is_boundary_logout_1d + module procedure li_mask_is_boundary_logout_0d + end interface + + + interface li_mask_is_boundary_int + module procedure li_mask_is_boundary_intout_1d + module procedure li_mask_is_boundary_intout_0d + end interface +!-------------------------------------------------------------------- ! ! Private module variables ! @@ -294,10 +306,10 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) logical :: isMargin logical :: isAlbanyMarginNeighbor logical :: aCellOnVertexHasIce, aCellOnVertexHasNoIce, aCellOnVertexHasDynamicIce, aCellOnVertexHasNoDynamicIce, & - aCellOnVertexIsFloating, aCellOnVertexIsFloatingAndDynamic, aCellOnVertexIsAlbanyActive + aCellOnVertexIsFloating, aCellOnVertexIsFloatingAndDynamic, aCellOnVertexIsAlbanyActive, aCellOnVertexIsDomainBoundary logical :: aCellOnVertexIsGrounded logical :: aCellOnEdgeHasIce, aCellOnEdgeHasNoIce, aCellOnEdgeHasDynamicIce, aCellOnEdgeHasNoDynamicIce, & - aCellOnEdgeIsFloating, aCellOnEdgeIsFloatingAndDynamic + aCellOnEdgeIsFloating, aCellOnEdgeIsFloatingAndDynamic, aCellOnEdgeIsDomainBoundary logical :: aCellOnEdgeIsGrounded logical :: aCellOnEdgeIsOpenOcean integer :: numCellsOnVertex @@ -473,6 +485,16 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) endif enddo + !identify domain boundaries + do i=1,nCells + do j=1,nEdgesOnCell(i) + iCellNeighbor = cellsOnCell(j,i) + if (iCellNeighbor == nCells+1) then + cellMask(i) = ior(cellMask(i), li_mask_ValueDomainBoundary) + endif + enddo + enddo + !call mpas_timer_stop('calculate mask cell') ! ==== @@ -503,6 +525,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) aCellOnVertexIsFloating = .false. aCellOnVertexIsGrounded = .false. aCellOnVertexIsFloatingAndDynamic = .false. + aCellOnVertexIsDomainBoundary = .false. do j = 1, vertexDegree ! vertexDegree is usually 3 (e.g. CVT mesh) but could be something else (e.g. 4 for quad mesh) iCell = cellsOnVertex(j,i) aCellOnVertexHasIce = (aCellOnVertexHasIce .or. li_mask_is_ice(cellMask(iCell))) @@ -514,7 +537,9 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) (li_mask_is_floating_ice(cellMask(iCell)) .and. & li_mask_is_dynamic_ice(cellMask(iCell))) ) aCellOnVertexIsGrounded = (aCellOnVertexIsGrounded .or. li_mask_is_grounded_ice(cellMask(iCell))) + aCellOnVertexIsDomainBoundary = (aCellOnVertexIsDomainBoundary .or. li_mask_is_boundary(cellMask(iCell))) end do + if (aCellOnVertexHasIce) then vertexMask(i) = ior(vertexMask(i), li_mask_ValueIce) endif @@ -535,6 +560,9 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) vertexMask(i) = ior(vertexMask(i), li_mask_ValueDynamicMargin) ! vertex with both 1+ dynamic ice cell(s) and 1+ non-dynamic cell(s) as neighbors endif + if (aCellOnVertexIsDomainBoundary) then + vertexMask(i) = ior(vertexMask(i), li_mask_ValueDomainBoundary) + endif end do @@ -607,6 +635,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) aCellOnEdgeIsGrounded = .false. aCellOnEdgeIsOpenOcean = .false. aCellOnEdgeIsFloatingAndDynamic = .false. + aCellOnEdgeIsDomainBoundary = .false. do j = 1, 2 iCell = cellsOnEdge(j,i) aCellOnEdgeHasIce = (aCellOnEdgeHasIce .or. li_mask_is_ice(cellMask(iCell))) @@ -620,6 +649,7 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) aCellOnEdgeIsGrounded = (aCellOnEdgeIsGrounded .or. li_mask_is_grounded_ice(cellMask(iCell))) aCellOnEdgeIsOpenOcean = aCellOnEdgeIsOpenOcean .or. & ((bedTopography(iCell) < config_sea_level) .and. (.not. li_mask_is_ice(cellMask(iCell)))) + aCellOnEdgeIsDomainBoundary = (aCellOnEdgeIsDomainBoundary .or. li_mask_is_boundary(cellMask(iCell))) end do if (aCellOnEdgeHasIce) then edgeMask(i) = ior(edgeMask(i), li_mask_ValueIce) @@ -641,6 +671,9 @@ subroutine li_calculate_mask(meshPool, velocityPool, geometryPool, err) if (aCellOnEdgeHasDynamicIce .and. aCellOnEdgeHasNoDynamicIce) then edgeMask(i) = ior(edgeMask(i), li_mask_ValueDynamicMargin) endif + if (aCellOnEdgeIsDomainBoundary) then + edgeMask(i) = ior(edgeMask(i), li_mask_ValueDomainBoundary) + endif end do !call mpas_timer_stop('calculate mask edge') @@ -905,8 +938,35 @@ function li_mask_is_initial_ice_logout_0d(mask) li_mask_is_initial_ice_logout_0d = (iand(mask, li_mask_ValueInitialIceExtent) == li_mask_ValueInitialIceExtent) end function li_mask_is_initial_ice_logout_0d + ! -- Functions that check for domain boundary -- + function li_mask_is_boundary_logout_1d(mask) + integer, dimension(:), intent(in) :: mask + logical, dimension(size(mask)) :: li_mask_is_boundary_logout_1d + + li_mask_is_boundary_logout_1d = (iand(mask, li_mask_ValueDomainBoundary) == li_mask_ValueDomainBoundary) + end function li_mask_is_boundary_logout_1d + + function li_mask_is_boundary_logout_0d(mask) + integer, intent(in) :: mask + logical :: li_mask_is_boundary_logout_0d + + li_mask_is_boundary_logout_0d = (iand(mask, li_mask_ValueDomainBoundary) == li_mask_ValueDomainBoundary) + end function li_mask_is_boundary_logout_0d + function li_mask_is_boundary_intout_1d(mask) + integer, dimension(:), intent(in) :: mask + integer, dimension(size(mask)) :: li_mask_is_boundary_intout_1d + + li_mask_is_boundary_intout_1d = iand(mask, li_mask_ValueDomainBoundary) / li_mask_ValueDomainBoundary + end function li_mask_is_boundary_intout_1d + + function li_mask_is_boundary_intout_0d(mask) + integer, intent(in) :: mask + integer :: li_mask_is_boundary_intout_0d + + li_mask_is_boundary_intout_0d = iand(mask, li_mask_ValueDomainBoundary) / li_mask_ValueDomainBoundary + end function li_mask_is_boundary_intout_0d !*********************************************************************** ! Private subroutines: !*********************************************************************** From dfa69eeeea3d08eeca86b090f07efc7c0f8f25c8 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 14 Jun 2023 17:38:01 -0600 Subject: [PATCH 183/388] Fix bug in iceThicknessHydro Commit Fixes bug in previous commit that introduces iceThicknessHydro --- .../mode_forward/mpas_li_subglacial_hydro.F | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 53e2edc9ee9..c67a3996f05 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -204,6 +204,11 @@ subroutine li_SGH_init(domain, err) block => block % next end do + !update halo for iceThicknessHydro + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'iceThicknessHydro') + call mpas_timer_stop("halo updates") + ! === error check if (err > 0) then call mpas_log_write("An error has occurred in li_SGH_init.", MPAS_LOG_ERR) @@ -339,6 +344,11 @@ subroutine li_SGH_solve(domain, err) block => block % next end do + !update halo for iceThicknessHydro + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'iceThicknessHydro') + call mpas_timer_stop("halo updates") + ! initialize while loop call mpas_pool_get_subpool(domain % blocklist % structs, 'mesh', meshPool) ! can get from any block call mpas_pool_get_array(meshPool, 'deltat', masterDeltat) @@ -2362,8 +2372,10 @@ subroutine calc_iceThicknessHydro(block, err) integer, pointer :: nCells integer :: iCell integer :: jCell + integer :: numCellsChanged + integer :: iNeighbor real (kind=RKIND) :: minNeighborHeight - real (kind=RKIND), parameter :: bigValue = 1.0_RKIND + real (kind=RKIND), parameter :: bigValue = 1.0e6_RKIND integer, dimension(:), pointer :: nEdgesOnCell err = 0 @@ -2382,27 +2394,36 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) iceThicknessHydro = thickness + numCellsChanged = 0 do iCell = 1, nCells - if ((li_mask_is_boundary(cellMask(iCell))) .and. (li_mask_is_grounded_ice(cellMask(iCell)))) then !identify domain boundaries - minNeighborHeight = bigValue !allocate + if ((li_mask_is_boundary(cellMask(iCell))) .and. & + (li_mask_is_grounded_ice(cellMask(iCell)))) then !identify domain boundaries + + minNeighborHeight = bigValue !allocate do jCell = 1, nEdgesOnCell(iCell) - if ( .not. li_mask_is_boundary(cellMask(cellsOnCell(jCell,iCell)))) then - minNeighborHeight = min(minNeighborHeight, upperSurface(cellsOnCell(jCell,iCell))) + iNeighbor = cellsOnCell(jCell,iCell) + if ( .not. li_mask_is_boundary(cellMask(iNeighbor)) .and. & + (iNeighbor < nCells + 1)) then + minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) endif end do !only adjust surface elevation if cell is local minimum if ((upperSurface(iCell) < minNeighborHeight) .and. (minNeighborHeight < bigValue)) then + call mpas_log_write("Changed ice thickness of cell $i", intArgs=(/iCell/)) + numCellsChanged = numCellsChanged + 1 iceThicknessHydro(iCell) = minNeighborHeight - bedTopography(iCell) endif endif enddo -!------------------------------------------------------------------------- - end subroutine calc_iceThicknessHydro + call mpas_log_write("Number of Cells Changed in iceThicknessHydro: $i", intArgs=(/numCellsChanged/)) + call mpas_log_write("Minimum Neighbor Height: $r", realArgs=(/minNeighborHeight/)) + + end subroutine calc_iceThicknessHydro !*********************************************************************** ! From c56a8a5cdea3a2db6f6820a499b6dcd69f58f561 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 19 Jun 2023 17:20:30 -0600 Subject: [PATCH 184/388] iceThicknessHydro additionally adjusts elev. highs 'iceThicknessHydro' now adjusts the ice thicknesses of boundary cells so that there are also no local maxima in surface elevation on the boundaries (in addition to the previous removal of local minima). This will make the surface elevation of all boundary cells equal to either the minimum or maximum of their non-boundary neighbors. This is done to avoid diffusivity instabilities when using the 'from_vertex_barycentric' tangent slope calculation. Currently, this implementation will change *all* grounded boundary cells, so this commit also introduces a new namelist option, 'config_SGH_use_iceThicknessHydro' that enables the 'iceThicknessHydro' calculation if set to '.true.'. 'iceThicknessHydro' is equivalent to 'thickness' when 'config_SGH_use_iceThicknessHydro' is false. 'config_SGH_use_iceThicknessHydro' has a default value of '.true.' --- .../src/Registry_subglacial_hydro.xml | 8 ++- .../mode_forward/mpas_li_subglacial_hydro.F | 66 ++++++++++++------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 2fae65a0de1..ba9f0948d46 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -77,7 +77,13 @@ description="notional englacial porosity" possible_values="positive real number" /> - + + + + maxNeighborHeight) .and. & + (maxNeighborHeight > bigNegativeValue)) then + numCellsChanged = numCellsChanged + 1 + iceThicknessHydro(iCell) = maxNeighborHeight - bedTopography(iCell) + endif - endif - enddo + endif + enddo - call mpas_log_write("Number of Cells Changed in iceThicknessHydro: $i", intArgs=(/numCellsChanged/)) - call mpas_log_write("Minimum Neighbor Height: $r", realArgs=(/minNeighborHeight/)) - + call mpas_log_write("Number of Cells Changed in iceThicknessHydro: $i", intArgs=(/numCellsChanged/)) + endif + end subroutine calc_iceThicknessHydro !*********************************************************************** From 45b1bf304e590c2b1a86fd3485756283eab9abb8 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 5 Jul 2023 10:01:32 -0600 Subject: [PATCH 185/388] iceThicknessHydro as mean of neighboring cells iceThicknessHydro now smooths the entire ice thickness field used by the subglacial hydrology model, instead of only smoothing along the boundaries. In the subglacial hydrology model, each cell's surface elevation is now a mean of its neighbors. As done previously, an additional requirement prohibits the surface elevation used by the subglacial hydrology model from being a local minimum or maximum. The purpose of this commit is to address issues arising from single-cell subglacial lakes that form when the surface elevation of a cell is lower than all of its neighbors, particularly when coupling to ice dynamics. --- .../mode_forward/mpas_li_subglacial_hydro.F | 72 +++++++++++++------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index bd94e2357af..20da6bf73e9 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2372,10 +2372,12 @@ subroutine calc_iceThicknessHydro(block, err) integer, pointer :: nCells integer :: iCell integer :: jCell - integer :: numCellsChanged integer :: iNeighbor real (kind=RKIND) :: minNeighborHeight real (kind=RKIND) :: maxNeighborHeight + real (kind=RKIND) :: meanNeighborHeight + real (kind=RKIND) :: totNeighborHeight + real (kind=RKIND) :: numCells real (kind=RKIND), parameter :: bigValue = 1.0e6_RKIND real (kind=RKIND), parameter :: bigNegativeValue = -1.0e6_RKIND integer, dimension(:), pointer :: nEdgesOnCell @@ -2396,6 +2398,7 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) call mpas_pool_get_config(liConfigs, 'config_SGH_use_iceThicknessHydro', config_SGH_use_iceThicknessHydro) + iceThicknessHydro = thickness !iceThicknessHydro is equivalent to thickness if @@ -2403,42 +2406,67 @@ subroutine calc_iceThicknessHydro(block, err) !ice thickness along boundaries. if (config_SGH_use_iceThicknessHydro) then - - numCellsChanged = 0 do iCell = 1, nCells - if ((li_mask_is_boundary(cellMask(iCell))) .and. & - (li_mask_is_grounded_ice(cellMask(iCell)))) then !identify domain boundaries - + if (li_mask_is_grounded_ice(cellMask(iCell))) then !identify domain boundaries + !Smooth by making each cell equal to the mean of its + !neighbors. + + do jCell = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jCell,iCell) + if (iNeighbor < nCells + 1) then + if (jCell == 1) then + totNeighborHeight = upperSurface(iNeighbor) + numCells = 1 + else + totNeighborHeight = totNeighborHeight + upperSurface(iNeighbor) + numCells = numCells + 1 + endif + endif + + meanNeighborHeight = totNeighborHeight / numCells + end do + + iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) + + !Above averaging is not sequential with respect to flow + !direction, so cells can still be local minima or maxima + !after smoothing. Find and correct cells where this is the case + minNeighborHeight = bigValue !allocate maxNeighborHeight = bigNegativeValue - + do jCell = 1, nEdgesOnCell(iCell) iNeighbor = cellsOnCell(jCell,iCell) - if (.not. li_mask_is_boundary(cellMask(iNeighbor)) .and. & - (iNeighbor < nCells + 1)) then - minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) - maxNeighborHeight = max(maxNeighborHeight, upperSurface(iNeighbor)) - endif + if (iNeighbor < nCells + 1) then + + minNeighborHeight = min(minNeighborHeight, iceThicknessHydro(iNeighbor) + & + bedTopography(iNeighbor)) + + maxNeighborHeight = max(maxNeighborHeight, iceThicknessHydro(iNeighbor) + & + bedTopography(iNeighbor)) + + endif end do - + !only adjust surface elevation if cell is local minimum or !maximum - if ((upperSurface(iCell) < minNeighborHeight) .and. (minNeighborHeight < bigValue)) then - numCellsChanged = numCellsChanged + 1 - iceThicknessHydro(iCell) = minNeighborHeight - bedTopography(iCell) - elseif ((upperSurface(iCell) > maxNeighborHeight) .and. & - (maxNeighborHeight > bigNegativeValue)) then - numCellsChanged = numCellsChanged + 1 + if (((iceThicknessHydro(iCell) + bedTopography(iCell)) < minNeighborHeight) & + .and. (minNeighborHeight < bigValue)) then + + iceThicknessHydro(iCell) = minNeighborHeight - bedTopography(iCell) + + elseif (((iceThicknessHydro(iCell) + bedTopography(iCell)) > maxNeighborHeight) & + .and. (maxNeighborHeight > bigNegativeValue)) then + iceThicknessHydro(iCell) = maxNeighborHeight - bedTopography(iCell) + endif endif enddo - - call mpas_log_write("Number of Cells Changed in iceThicknessHydro: $i", intArgs=(/numCellsChanged/)) endif - + end subroutine calc_iceThicknessHydro !*********************************************************************** From 9407999931416f47b28d24070170031b2ef62508 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 7 Jul 2023 15:46:23 -0600 Subject: [PATCH 186/388] Limit iceThicknessHydro to non-margin cells Disallow iceThicknessHydro modification at ice margins. Avoids bug where iceThicknessHydro can be negative at certain ice margin cells --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 20da6bf73e9..6c0c000dee1 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -1610,7 +1610,7 @@ subroutine calc_pressure(block, err) waterPressure = max(0.0_RKIND, waterPressure) waterPressure = min(waterPressure, rhoi * gravity * iceThicknessHydro) - + do iCell = 1, nCells if ( li_mask_is_floating_ice(cellMask(iCell)) .or. & ((.not. li_mask_is_ice(cellMask(iCell))) .and. (bedTopography(iCell) < config_sea_level) ) ) then @@ -1711,7 +1711,7 @@ subroutine calc_pressure_diag_vars(block, err) where (.not. li_mask_is_grounded_ice(cellmask)) effectivePressure = 0.0_RKIND ! zero effective pressure where no ice to avoid confusion end where - + hydropotentialBase = rho_water * gravity * bedTopography + waterPressure ! This is still correct under ice shelves/open ocean because waterPressure has been set appropriately there already. ! Note this leads to a nonuniform hydropotential at sea level that is a function of the ocean depth. @@ -2408,7 +2408,7 @@ subroutine calc_iceThicknessHydro(block, err) if (config_SGH_use_iceThicknessHydro) then do iCell = 1, nCells - if (li_mask_is_grounded_ice(cellMask(iCell))) then !identify domain boundaries + if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then !identify domain boundaries !Smooth by making each cell equal to the mean of its !neighbors. From 0c3e53e62b13905a2b438db4a516a458d7e94dc9 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 18 Jul 2023 14:34:26 -0600 Subject: [PATCH 187/388] iceThicknessHydro limited to local min/max Changes calculation of iceThicknessHydro and limits its affect to only local min/max. Previously iceThicknessHydro smoothed every cell by making it a mean of its neighbors, but this unrealistically flattened hydropotential gradients for ice sheet wide simulations. iceThicknessHydro is now adjusts the ice thickness of only local min/max so that their surface elevation is equal to the mean of their neighbors. This commit also introduces upperSurfaceHydro as an output variable in the hydro pool. --- .../src/Registry_subglacial_hydro.xml | 2 + .../mode_forward/mpas_li_subglacial_hydro.F | 57 ++++++++----------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index ba9f0948d46..32efc089c74 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -148,6 +148,8 @@ + maxNeighborHeight) & + elseif ((upperSurface(iCell) > maxNeighborHeight) & .and. (maxNeighborHeight > bigNegativeValue)) then - iceThicknessHydro(iCell) = maxNeighborHeight - bedTopography(iCell) + iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) endif @@ -2467,6 +2454,8 @@ subroutine calc_iceThicknessHydro(block, err) enddo endif + upperSurfaceHydro = iceThicknessHydro + bedTopography + end subroutine calc_iceThicknessHydro !*********************************************************************** From 2e1400f91edc4c63adf028ac63ce0b0fb3ea4928 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Thu, 20 Jul 2023 16:21:26 -0600 Subject: [PATCH 188/388] Debug iceThicknessHydro Addresses a couple small bugs found in iceThicknessHydro. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 97cc2d1ebfd..c4912d9e045 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2412,19 +2412,19 @@ subroutine calc_iceThicknessHydro(block, err) do iCell = 1, nCells if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then !identify domain boundaries - maxNeighborHeight = bigValue !allocate - minNeighborHeight = bigNegativeValue + maxNeighborHeight = bigNegativeValue !allocate + minNeighborHeight = bigValue do jCell = 1, nEdgesOnCell(iCell) iNeighbor = cellsOnCell(jCell,iCell) - if (jCell == 1) then - totNeighborHeight = upperSurface(iNeighbor) - numCells = 1 - endif - if (iNeighbor < nCells + 1) then + if (jCell == 1) then + totNeighborHeight = upperSurface(iNeighbor) + numCells = 1 + endif + minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) maxNeighborHeight = max(maxNeighborHeight, upperSurface(iNeighbor)) From 0ad0388946f705192d723c2890b8c6398baca855 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 8 Sep 2023 10:08:49 -0700 Subject: [PATCH 189/388] avoid negative iceThicknessHydro Defaults iceThicknessHydro to original thickness if below zero --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index c4912d9e045..3675f1185e1 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2450,6 +2450,11 @@ subroutine calc_iceThicknessHydro(block, err) endif + !avoid negatives, default to original thickness + if (iceThicknessHydro(iCell) < 0.0_RKIND) then + iceThicknessHydro(iCell) = thickness(iCell) + endif + endif enddo endif From 88beec159d3900b48336d3429919b57fc307f5af Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 26 Sep 2023 12:49:37 -0700 Subject: [PATCH 190/388] no iceThicknessHydro at GL Disables iceThicknessHydro at grounding line so not ocean properties are included in calculation --- .../mode_forward/mpas_li_subglacial_hydro.F | 88 ++++++++++++------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 3675f1185e1..4e402062cc8 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2368,12 +2368,19 @@ subroutine calc_iceThicknessHydro(block, err) real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro real (kind=RKIND), dimension(:), pointer :: upperSurfaceHydro real (kind=RKIND), dimension(:), pointer :: upperSurface + integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:,:), pointer :: cellsOnCell + integer, dimension(:,:), pointer :: edgesOnCell integer, dimension(:), pointer :: cellMask + integer, dimension(:), pointer :: edgeMask integer, pointer :: nCells + integer :: edgeNum + integer, dimension(:), pointer :: nEdgesOnCell + integer :: iEdge integer :: iCell integer :: jCell integer :: iNeighbor + integer :: isMarineMargin real (kind=RKIND) :: maxNeighborHeight real (kind=RKIND) :: minNeighborHeight real (kind=RKIND) :: meanNeighborHeight @@ -2381,7 +2388,6 @@ subroutine calc_iceThicknessHydro(block, err) real (kind=RKIND) :: numCells real (kind=RKIND), parameter :: bigValue = 1.0e6_RKIND real (kind=RKIND), parameter :: bigNegativeValue = -1.0e6_RKIND - integer, dimension(:), pointer :: nEdgesOnCell logical, pointer :: config_SGH_use_iceThicknessHydro err = 0 @@ -2393,12 +2399,16 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) + call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) call mpas_pool_get_array(hydroPool, 'upperSurfaceHydro', upperSurfaceHydro) call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) + call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) + call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) + call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_config(liConfigs, 'config_SGH_use_iceThicknessHydro', config_SGH_use_iceThicknessHydro) iceThicknessHydro = thickness @@ -2408,53 +2418,63 @@ subroutine calc_iceThicknessHydro(block, err) !ice thickness if (config_SGH_use_iceThicknessHydro) then - do iCell = 1, nCells - if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then !identify domain boundaries - maxNeighborHeight = bigNegativeValue !allocate - minNeighborHeight = bigValue + if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then !identify domain boundaries - do jCell = 1, nEdgesOnCell(iCell) - iNeighbor = cellsOnCell(jCell,iCell) + isMarineMargin = 0 + do edgeNum = 1, nEdgesOnCell(iCell) + iEdge = edgesOnCell(edgeNum,iCell) + if (hydroMarineMarginMask(iEdge) == 1) then + isMarineMargin = 1 + exit + endif + enddo - if (iNeighbor < nCells + 1) then + if (isMarineMargin == 0) then + maxNeighborHeight = bigNegativeValue !allocate + minNeighborHeight = bigValue + + do jCell = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jCell,iCell) - if (jCell == 1) then - totNeighborHeight = upperSurface(iNeighbor) - numCells = 1 - endif - - minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) + if (iNeighbor < nCells + 1) then - maxNeighborHeight = max(maxNeighborHeight, upperSurface(iNeighbor)) + if (jCell == 1) then + totNeighborHeight = upperSurface(iNeighbor) + numCells = 1 + endif + + minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) - totNeighborHeight = totNeighborHeight + upperSurface(iNeighbor) - numCells = numCells + 1 - endif - end do + maxNeighborHeight = max(maxNeighborHeight, upperSurface(iNeighbor)) - meanNeighborHeight = totNeighborHeight / numCells + totNeighborHeight = totNeighborHeight + upperSurface(iNeighbor) + numCells = numCells + 1 + endif + end do - !only adjust surface elevation if cell is local minimum or - !maximum - if ((upperSurface(iCell) < minNeighborHeight) & - .and. (minNeighborHeight < bigValue)) then + meanNeighborHeight = totNeighborHeight / numCells - iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) + !only adjust surface elevation if cell is local minimum or + !maximum + if ((upperSurface(iCell) < minNeighborHeight) & + .and. (minNeighborHeight < bigValue)) then - elseif ((upperSurface(iCell) > maxNeighborHeight) & - .and. (maxNeighborHeight > bigNegativeValue)) then + iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) - iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) + elseif ((upperSurface(iCell) > maxNeighborHeight) & + .and. (maxNeighborHeight > bigNegativeValue)) then - endif + iceThicknessHydro(iCell) = meanNeighborHeight - bedTopography(iCell) - !avoid negatives, default to original thickness - if (iceThicknessHydro(iCell) < 0.0_RKIND) then - iceThicknessHydro(iCell) = thickness(iCell) - endif - + endif + + !avoid negatives, default to original thickness + if (iceThicknessHydro(iCell) < 0.0_RKIND) then + iceThicknessHydro(iCell) = thickness(iCell) + endif + endif endif enddo endif From f728bb34c8c4ec468cfe16b381dda49fc329c1c6 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Thu, 4 Jan 2024 15:05:04 -0800 Subject: [PATCH 191/388] Add waterPressureSmooth Adds smoothed water pressure field, waterPressureSmooth, that is used only for calculation of waterPressureSlopeNormal and channelPressureFreeze. Option config_SGH_iter_smooth_waterPressureSlopeNormal specifies number of times to smooth waterPressure over when calculating waterPressureSlopeNormal --- .../src/Registry_subglacial_hydro.xml | 13 ++- .../mode_forward/mpas_li_subglacial_hydro.F | 92 +++++++++++++++++-- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 32efc089c74..ecbcb89a48b 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -125,6 +125,10 @@ possible_values="'file', 'thermal', 'basal_heat'" /> + @@ -162,7 +166,9 @@ description="water layer thickness in subglacial till from previous time step" /> - + @@ -239,7 +245,7 @@ + description="time step used for evolving subglacial hydrology system" /> + + 0) then + do iter = 1, nTimesSmooth !May need to iterate to smooth properly + if (iter == 1) then + waterPressureSmooth = waterPressure + pressureField = waterPressure + else + pressureField = waterPressureSmooth + endif + + do iCell = 1, nCells + if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then + + isMarineMargin = 0 + do edgeNum = 1, nEdgesOnCell(iCell) + iEdge = edgesOnCell(edgeNum,iCell) + if (hydroMarineMarginMask(iEdge) == 1) then + isMarineMargin = 1 + exit + endif + enddo + + if (isMarineMargin == 0) then + + totNeighborPressure = pressureField(iCell) + numCells = 1 + + do jCell = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jCell,iCell) + + if (iNeighbor < nCells + 1) then + totNeighborPressure = totNeighborPressure + pressureField(iNeighbor) + numCells = numCells + 1 + endif + end do + + !waterPressureSmooth is average of neighboring cells + waterPressureSmooth(iCell) = totNeighborPressure / numCells + endif + endif + end do + end do + elseif (nTimesSmooth == 0) then + waterPressureSmooth = waterPressure + endif + + do iEdge = 1, nEdges + cell1 = cellsOnEdge(1, iEdge) + cell2 = cellsOnEdge(2, iEdge) + + waterPressureSlopeNormal(iEdge) = (waterPressureSmooth(cell2) - waterPressureSmooth(cell1)) / dcEdge(iEdge) end do ! At boundaries of hydro domain, disallow inflow. Allow outflow if hydropotential gradient requires it. From e7fba6bdedb0a016846db8cef834543167678179 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 28 Feb 2024 15:03:37 -0700 Subject: [PATCH 192/388] Adjust iceThicknessHydro logic + implementation Addresses comments in original PR about iceThicknessHydro. iceThickness hydro is now calculated for all grounded ice cells, including ice margins and the grounding line, but neighboring cells are only included in averaging calculation if they are also grounded cells. iceThicknessHydro is now an area-weighted average of neighboring cells that replaces local minima and maxima. --- .../src/Registry_subglacial_hydro.xml | 2 +- .../mode_forward/mpas_li_subglacial_hydro.F | 48 +++++++++---------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index ecbcb89a48b..143497036c1 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -79,7 +79,7 @@ /> diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 2b0986249c1..d708f79eca5 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2449,6 +2449,7 @@ subroutine calc_iceThicknessHydro(block, err) integer, dimension(:,:), pointer :: edgesOnCell integer, dimension(:), pointer :: cellMask integer, dimension(:), pointer :: edgeMask + real (kind=RKIND), dimension(:), pointer :: areaCell integer, pointer :: nCells integer :: edgeNum integer, dimension(:), pointer :: nEdgesOnCell @@ -2456,12 +2457,11 @@ subroutine calc_iceThicknessHydro(block, err) integer :: iCell integer :: jCell integer :: iNeighbor - integer :: isMarineMargin real (kind=RKIND) :: maxNeighborHeight real (kind=RKIND) :: minNeighborHeight real (kind=RKIND) :: meanNeighborHeight - real (kind=RKIND) :: totNeighborHeight - real (kind=RKIND) :: numCells + real (kind=RKIND) :: totalNeighborHeight + real (kind=RKIND) :: totalArea real (kind=RKIND), parameter :: bigValue = 1.0e6_RKIND real (kind=RKIND), parameter :: bigNegativeValue = -1.0e6_RKIND logical, pointer :: config_SGH_use_iceThicknessHydro @@ -2484,6 +2484,7 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) + call mpas_pool_get_array(meshPool, 'areaCell', areaCell) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_config(liConfigs, 'config_SGH_use_iceThicknessHydro', config_SGH_use_iceThicknessHydro) @@ -2496,41 +2497,37 @@ subroutine calc_iceThicknessHydro(block, err) if (config_SGH_use_iceThicknessHydro) then do iCell = 1, nCells - if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then !identify domain boundaries + if (li_mask_is_grounded_ice(cellMask(iCell))) then !identify domain boundaries - isMarineMargin = 0 - do edgeNum = 1, nEdgesOnCell(iCell) - iEdge = edgesOnCell(edgeNum,iCell) - if (hydroMarineMarginMask(iEdge) == 1) then - isMarineMargin = 1 - exit - endif - enddo - - if (isMarineMargin == 0) then - maxNeighborHeight = bigNegativeValue !allocate + maxNeighborHeight = bigNegativeValue !initialize minNeighborHeight = bigValue + totalNeighborHeight = 0.0_RKIND + totalArea = 0.0_RKIND + do jCell = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jCell,iCell) - if (iNeighbor < nCells + 1) then + !Only include neighbor cell in averaging if it contains grounded ice + if ((li_mask_is_grounded_ice(cellMask(iNeighbor)))) then - if (jCell == 1) then - totNeighborHeight = upperSurface(iNeighbor) - numCells = 1 - endif - minNeighborHeight = min(minNeighborHeight, upperSurface(iNeighbor)) maxNeighborHeight = max(maxNeighborHeight, upperSurface(iNeighbor)) - totNeighborHeight = totNeighborHeight + upperSurface(iNeighbor) - numCells = numCells + 1 + totalNeighborHeight = totalNeighborHeight + upperSurface(iNeighbor)*areaCell(iNeighbor) + + totalArea = totalArea + areaCell(iNeighbor) + endif end do - - meanNeighborHeight = totNeighborHeight / numCells + + if ((totalNeighborHeight == 0.0_RKIND) .or. (totalArea == 0.0_RKIND)) then + meanNeighborHeight = upperSurface(iCell) !no smoothing in single-cell islands + else + meanNeighborHeight = totalNeighborHeight / totalArea !area-weighted average height + endif !only adjust surface elevation if cell is local minimum or !maximum @@ -2550,7 +2547,6 @@ subroutine calc_iceThicknessHydro(block, err) if (iceThicknessHydro(iCell) < 0.0_RKIND) then iceThicknessHydro(iCell) = thickness(iCell) endif - endif endif enddo endif From e76d9a96abc804430fb78f8adf7fa625eebf6c98 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 4 Mar 2024 10:17:42 -0700 Subject: [PATCH 193/388] waterPressure area-weighted mean subroutine Addresses PR comments regarding waterPressureSmooth, namely, moving waterPressureSmooth calculation to its own subroutine, making waterPressureSmooth an area-weighted mean of the current cell and its neighbors, and adding halo updates. Please enter the commit message for your changes. Lines starting --- .../src/Registry_subglacial_hydro.xml | 3 - .../mode_forward/mpas_li_subglacial_hydro.F | 200 +++++++++++------- 2 files changed, 123 insertions(+), 80 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 143497036c1..87af56eee82 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -253,9 +253,6 @@ - - block % next end do @@ -302,8 +310,6 @@ subroutine li_SGH_solve(domain, err) integer :: numSubCycles ! number of subcycles integer :: err_tmp - - err = 0 err_tmp = 0 @@ -641,6 +647,14 @@ subroutine li_SGH_solve(domain, err) call calc_pressure(block, err_tmp) err = ior(err, err_tmp) + + call calc_waterPressureSmooth(block, err_tmp) !adjust ice thickness along boundaries + err = ior(err,err_tmp) + + !updates halos for waterPressure + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'waterPressureSlopeNormal') + call mpas_timer_stop("halo updates") block => block % next end do @@ -777,7 +791,6 @@ subroutine calc_edge_quantities(block, err) real (kind=RKIND), dimension(:), pointer :: hydropotentialBaseVertex real (kind=RKIND), dimension(:), pointer :: hydropotentialVertex real (kind=RKIND), dimension(:), pointer :: waterPressure - real (kind=RKIND), dimension(:), pointer :: waterPressureSmooth real (kind=RKIND), dimension(:), pointer :: waterThicknessEdge real (kind=RKIND), dimension(:), pointer :: waterThicknessEdgeUpwind real (kind=RKIND), dimension(:), pointer :: waterThickness @@ -796,8 +809,7 @@ subroutine calc_edge_quantities(block, err) real (kind=RKIND), dimension(:), pointer :: waterFlux real (kind=RKIND), dimension(:), pointer :: waterFluxAdvec real (kind=RKIND), dimension(:), pointer :: waterFluxDiffu - real (kind=RKIND), dimension(:), pointer :: channelDebugMask - real (kind=RKIND), dimension(:), pointer :: pressureField + real (kind=RKIND), dimension(:), pointer :: waterPressureSmooth integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:), pointer :: waterFluxMask integer, dimension(:,:), pointer :: edgeSignOnCell @@ -832,7 +844,6 @@ subroutine calc_edge_quantities(block, err) integer :: iNeighbor integer :: numCells integer :: iter - real (kind=RKIND) :: totNeighborPressure err = 0 err_tmp = 0 @@ -858,7 +869,6 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) - call mpas_pool_get_array(hydroPool, 'waterPressureSmooth', waterPressureSmooth) call mpas_pool_get_array(hydroPool, 'hydropotentialBase', hydropotentialBase) call mpas_pool_get_array(hydroPool, 'hydropotential', hydropotential) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) @@ -888,9 +898,8 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_array(hydroPool, 'waterFluxMask', waterFluxMask) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - call mpas_pool_get_array(hydroPool, 'channelDebugMask', channelDebugMask) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) - call mpas_pool_get_array(hydroPool, 'pressureField', pressureField) + call mpas_pool_get_array(hydroPool, 'waterPressureSmooth', waterPressureSmooth) do iEdge = 1, nEdges cell1 = cellsOnEdge(1, iEdge) @@ -908,63 +917,7 @@ subroutine calc_edge_quantities(block, err) hydropotentialBaseSlopeNormal(iEdge) = (hydropotentialBase(cell2) - hydropotentialBase(cell1)) / dcEdge(iEdge) hydropotentialSlopeNormal(iEdge) = (hydropotential(cell2) - hydropotential(cell1)) / dcEdge(iEdge) - !waterPressureSlopeNormal(iEdge) = (waterPressure(cell2) - waterPressure(cell1)) / dcEdge(iEdge) - end do - - ! Create a smoothed waterPressure product used only for - ! calculating waterPressureSlopeNormal - to avoid channelPressureFreeze - ! instabilities - - if (nTimesSmooth > 0) then - do iter = 1, nTimesSmooth !May need to iterate to smooth properly - if (iter == 1) then - waterPressureSmooth = waterPressure - pressureField = waterPressure - else - pressureField = waterPressureSmooth - endif - - do iCell = 1, nCells - if ((li_mask_is_grounded_ice(cellMask(iCell))) .and. (.not. li_mask_is_margin(cellMask(iCell)))) then - - isMarineMargin = 0 - do edgeNum = 1, nEdgesOnCell(iCell) - iEdge = edgesOnCell(edgeNum,iCell) - if (hydroMarineMarginMask(iEdge) == 1) then - isMarineMargin = 1 - exit - endif - enddo - - if (isMarineMargin == 0) then - - totNeighborPressure = pressureField(iCell) - numCells = 1 - - do jCell = 1, nEdgesOnCell(iCell) - iNeighbor = cellsOnCell(jCell,iCell) - - if (iNeighbor < nCells + 1) then - totNeighborPressure = totNeighborPressure + pressureField(iNeighbor) - numCells = numCells + 1 - endif - end do - - !waterPressureSmooth is average of neighboring cells - waterPressureSmooth(iCell) = totNeighborPressure / numCells - endif - endif - end do - end do - elseif (nTimesSmooth == 0) then - waterPressureSmooth = waterPressure - endif - - do iEdge = 1, nEdges - cell1 = cellsOnEdge(1, iEdge) - cell2 = cellsOnEdge(2, iEdge) - waterPressureSlopeNormal(iEdge) = (waterPressureSmooth(cell2) - waterPressureSmooth(cell1)) / dcEdge(iEdge) end do @@ -1751,7 +1704,6 @@ subroutine calc_pressure_diag_vars(block, err) type (mpas_pool_type), pointer :: geometryPool type (mpas_pool_type), pointer :: hydroPool real (kind=RKIND), pointer :: rhoi, rhoo - real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: waterPressure real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: hydropotentialBase @@ -1773,7 +1725,6 @@ subroutine calc_pressure_diag_vars(block, err) call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhoo) call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure) - call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'hydropotentialBase', hydropotentialBase) @@ -2255,7 +2206,6 @@ subroutine ocean_connection_N(domain) type (block_type), pointer :: block type (mpas_pool_type), pointer :: hydroPool type (mpas_pool_type), pointer :: geometryPool - real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: effectivePressure real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro @@ -2270,7 +2220,6 @@ subroutine ocean_connection_N(domain) do while (associated(block)) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) - call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) @@ -2413,8 +2362,8 @@ end subroutine calc_hydro_mask !> \author Alex Hager !> \date 7 June 2023 !> \details -!> This routine calculates a modified ice thickness that is altered at -! the domain boundaries to avoid local minima in hydropotential +!> This routine calculates a modified ice thickness that is altered to +!> avoid local minima in hydropotential !----------------------------------------------------------------------- subroutine calc_iceThicknessHydro(block, err) @@ -2566,7 +2515,6 @@ end subroutine calc_iceThicknessHydro !> \details Find the total amount of freshwater entering the first ocean cell from the grounding line. !----------------------------------------------------------------------- subroutine calc_gl_totals(block, err) - !----------------------------------------------------------------- ! input variables !----------------------------------------------------------------- @@ -2581,11 +2529,6 @@ subroutine calc_gl_totals(block, err) !----------------------------------------------------------------- integer, intent(out) :: err !< Output: error flag - !----------------------------------------------------------------- - !----------------------------------------------------------------- - ! output variables - !----------------------------------------------------------------- - !----------------------------------------------------------------- ! local variables !----------------------------------------------------------------- @@ -2653,4 +2596,107 @@ subroutine calc_gl_totals(block, err) enddo end subroutine calc_gl_totals +!*********************************************************************** +! +! routine calc_waterPressureSmooth +! +!> \brief Calculate smoothed version of waterPressure used for calculation +!> of waterPressureSlopeNormal +!> \author Alex Hager +!> \date 29 February 2024 +!> \details Creates a smoothed version of waterPressure, called waterPressureSmooth, +!> that is used for calculation of waterPressureSlopeNormal. +!> This is necessary to increase stability with channelPressureFreeze +!> with spatially variable bedTopography and upperSurface. waterPressureSmooth +!> an area-weighted average of the current cells and its neighbors. Possible to +!> perform multiple iterations of smoothing by adjusting +!> config_SGH_iter_smooth_waterPressureSlopeNormal +!----------------------------------------------------------------------- + subroutine calc_waterPressureSmooth(block,err) + !----------------------------------------------------------------- + ! input variables + !----------------------------------------------------------------- + + !----------------------------------------------------------------- + ! input/output variables + !----------------------------------------------------------------- + type (block_type), intent(inout) :: block !< Input/Output: block object + + !----------------------------------------------------------------- + ! output variables + !----------------------------------------------------------------- + integer, intent(out) :: err !< Output: error flag + + !----------------------------------------------------------------- + ! local variables + !----------------------------------------------------------------- + + type (mpas_pool_type), pointer :: meshPool + type (mpas_pool_type), pointer :: geometryPool + type (mpas_pool_type), pointer :: hydroPool + real (kind=RKIND), dimension(:), pointer :: bedTopography + real (kind=RKIND), dimension(:), pointer :: waterPressure + real (kind=RKIND), dimension(:), pointer :: waterPressureSmooth + real (kind=RKIND), dimension(:), pointer :: areaCell + real (kind=RKIND), dimension(:), allocatable :: pressureField + real(kind=RKIND) :: totalPressure + real(kind=RKIND) :: totalArea + integer, dimension(:), pointer :: cellMask + integer, dimension(:,:), pointer :: cellsOnCell + integer, dimension(:), pointer :: nEdgesOnCell + integer, pointer :: nTimesSmooth + integer, pointer :: nCells + integer :: iCell, jCell + integer :: iNeighbor + integer :: iter + + err = 0 + + ! Get pools things + call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) + call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) + call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + call mpas_pool_get_config(liConfigs, 'config_SGH_iter_smooth_waterPressureSlopeNormal', nTimesSmooth) + call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) + call mpas_pool_get_array(hydroPool, 'waterPressureSmooth', waterPressureSmooth) + call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) + call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) + call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) + call mpas_pool_get_array(meshPool, 'areaCell', areaCell) + allocate(pressureField(nCells+1)) + + waterPressureSmooth = waterPressure + pressureField = waterPressure + + do iter = 1, nTimesSmooth !May need to iterate to smooth properly + + do iCell = 1, nCells + if (li_mask_is_grounded_ice(cellMask(iCell))) then !smooth over all grounded cells + + totalPressure = pressureField(iCell) + totalArea = areaCell(iCell) + + do jCell = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jCell,iCell) + + if ((li_mask_is_grounded_ice(cellMask(iNeighbor)))) then + + totalPressure = totalPressure + pressureField(iNeighbor)*areaCell(iNeighbor) + + totalArea = totalArea + areaCell(iNeighbor) + endif + end do + + waterPressureSmooth(iCell) = totalPressure / totalArea !area-weighted average height + endif + end do + + pressureField = waterPressureSmooth + + end do + + deallocate(pressureField) + end subroutine calc_waterPressureSmooth + end module li_subglacial_hydro From 1f94eb5e39f32f136c6b4e0579817d3fdde2e10b Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Mon, 4 Mar 2024 11:00:18 -0700 Subject: [PATCH 194/388] Debug waterPressureSmooth fixes minor bug in waterPRessureSmooth calculation --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index f74351f14ae..a7f39e2c830 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2674,7 +2674,7 @@ subroutine calc_waterPressureSmooth(block,err) do iCell = 1, nCells if (li_mask_is_grounded_ice(cellMask(iCell))) then !smooth over all grounded cells - totalPressure = pressureField(iCell) + totalPressure = pressureField(iCell)*areaCell(iCell) totalArea = areaCell(iCell) do jCell = 1, nEdgesOnCell(iCell) @@ -2688,7 +2688,7 @@ subroutine calc_waterPressureSmooth(block,err) endif end do - waterPressureSmooth(iCell) = totalPressure / totalArea !area-weighted average height + waterPressureSmooth(iCell) = totalPressure / totalArea !area-weighted average pressure endif end do From 435acd54def3fe98bbc8d714058859bc0841f34f Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Fri, 8 Mar 2024 11:39:42 -0700 Subject: [PATCH 195/388] PR cleanup Implements minor edits to PR to clean up code and debug halo updates --- .../mode_forward/mpas_li_subglacial_hydro.F | 77 +++++++++---------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index a7f39e2c830..2724921170d 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -181,12 +181,29 @@ subroutine li_SGH_init(domain, err) tillWaterThickness = max(0.0_RKIND, tillWaterThickness) tillWaterThickness = min(tillMax, tillWaterThickness) - call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) call calc_iceThicknessHydro(block, err_tmp) !adjust ice thickness along boundaries err = ior(err,err_tmp) + block => block % next + end do + + !update halo for iceThicknessHydro + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'iceThicknessHydro') + call mpas_timer_stop("halo updates") + + block => domain % blocklist + do while (associated(block)) + call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) + call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) + call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) + call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) + call mpas_pool_get_array(hydroPool, 'deltatSGH', deltatSGH) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) + waterPressure = max(0.0_RKIND, waterPressure) waterPressure = min(waterPressure, rhoi * gravity * iceThicknessHydro) ! set pressure correctly under floating ice and open ocean @@ -201,22 +218,18 @@ subroutine li_SGH_init(domain, err) call calc_pressure_diag_vars(block, err_tmp) err = ior(err, err_tmp) - call calc_waterPressureSmooth(block, err_tmp) !adjust ice thickness along boundaries + !smooth water pressure for calculation of waterPressureSlopeNormal + call calc_waterPressureSmooth(block, err_tmp) err = ior(err,err_tmp) - !updates halos for waterPressure - call mpas_timer_start("halo updates") - call mpas_dmpar_field_halo_exch(domain, 'waterPressureSlopeNormal') - call mpas_timer_stop("halo updates") - block => block % next end do - !update halo for iceThicknessHydro + !updates halos for waterPressure call mpas_timer_start("halo updates") - call mpas_dmpar_field_halo_exch(domain, 'iceThicknessHydro') + call mpas_dmpar_field_halo_exch(domain, 'waterPressureSmooth') call mpas_timer_stop("halo updates") - + ! === error check if (err > 0) then call mpas_log_write("An error has occurred in li_SGH_init.", MPAS_LOG_ERR) @@ -651,14 +664,14 @@ subroutine li_SGH_solve(domain, err) call calc_waterPressureSmooth(block, err_tmp) !adjust ice thickness along boundaries err = ior(err,err_tmp) - !updates halos for waterPressure - call mpas_timer_start("halo updates") - call mpas_dmpar_field_halo_exch(domain, 'waterPressureSlopeNormal') - call mpas_timer_stop("halo updates") - block => block % next end do + !updates halos for waterPressure + call mpas_timer_start("halo updates") + call mpas_dmpar_field_halo_exch(domain, 'waterPressureSmooth') + call mpas_timer_stop("halo updates") + ! ============= ! ============= @@ -818,7 +831,6 @@ subroutine calc_edge_quantities(block, err) integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:,:), pointer :: edgesOnCell integer, dimension(:,:), pointer :: cellsOnCell - integer, dimension(:), pointer :: nEdgesOnCell integer, dimension(:,:), pointer :: verticesOnEdge integer, dimension(:,:), pointer :: baryCellsOnVertex real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex @@ -830,12 +842,11 @@ subroutine calc_edge_quantities(block, err) character (len=StrKIND), pointer :: config_SGH_tangent_slope_calculation real (kind=RKIND), pointer :: config_sea_level real (kind=RKIND), pointer :: rhoo - integer, pointer :: nTimesSmooth integer, pointer :: nEdges integer, pointer :: nCells integer, pointer :: nVertices integer :: iEdge, cell1, cell2 - integer :: i, j, iVertex, iCell, jCell + integer :: i, j, iVertex, iCell real (kind=RKIND) :: velSign integer :: numGroundedCells integer :: err_tmp @@ -843,7 +854,6 @@ subroutine calc_edge_quantities(block, err) integer :: edgeNum integer :: iNeighbor integer :: numCells - integer :: iter err = 0 err_tmp = 0 @@ -865,7 +875,6 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_config(liConfigs, 'config_SGH_tangent_slope_calculation', config_SGH_tangent_slope_calculation) call mpas_pool_get_config(liConfigs, 'config_sea_level', config_sea_level) call mpas_pool_get_config(liConfigs, 'config_ocean_density', rhoo) - call mpas_pool_get_config(liConfigs, 'config_SGH_iter_smooth_waterPressureSlopeNormal', nTimesSmooth) call mpas_pool_get_array(hydroPool, 'waterThickness', waterThickness) call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) @@ -883,7 +892,6 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) - call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_array(meshPool, 'edgeSignOnCell', edgeSignOnCell) call mpas_pool_get_array(hydroPool, 'hydropotentialBaseSlopeTangent', hydropotentialBaseSlopeTangent) call mpas_pool_get_array(hydroPool, 'hydropotentialSlopeTangent', hydropotentialSlopeTangent) @@ -898,7 +906,6 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_array(hydroPool, 'waterFluxMask', waterFluxMask) call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) - call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_array(hydroPool, 'waterPressureSmooth', waterPressureSmooth) do iEdge = 1, nEdges @@ -2393,16 +2400,11 @@ subroutine calc_iceThicknessHydro(block, err) real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro real (kind=RKIND), dimension(:), pointer :: upperSurfaceHydro real (kind=RKIND), dimension(:), pointer :: upperSurface - integer, dimension(:), pointer :: hydroMarineMarginMask integer, dimension(:,:), pointer :: cellsOnCell - integer, dimension(:,:), pointer :: edgesOnCell integer, dimension(:), pointer :: cellMask - integer, dimension(:), pointer :: edgeMask real (kind=RKIND), dimension(:), pointer :: areaCell integer, pointer :: nCells - integer :: edgeNum integer, dimension(:), pointer :: nEdgesOnCell - integer :: iEdge integer :: iCell integer :: jCell integer :: iNeighbor @@ -2424,17 +2426,14 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_array(geometryPool, 'thickness', thickness) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) - call mpas_pool_get_array(geometryPool, 'edgeMask', edgeMask) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) call mpas_pool_get_array(hydroPool, 'upperSurfaceHydro', upperSurfaceHydro) call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) - call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_array(meshPool, 'areaCell', areaCell) - call mpas_pool_get_array(hydroPool, 'hydroMarineMarginMask', hydroMarineMarginMask) call mpas_pool_get_config(liConfigs, 'config_SGH_use_iceThicknessHydro', config_SGH_use_iceThicknessHydro) iceThicknessHydro = thickness @@ -2446,7 +2445,7 @@ subroutine calc_iceThicknessHydro(block, err) if (config_SGH_use_iceThicknessHydro) then do iCell = 1, nCells - if (li_mask_is_grounded_ice(cellMask(iCell))) then !identify domain boundaries + if (li_mask_is_grounded_ice(cellMask(iCell))) then !identify grounded ice maxNeighborHeight = bigNegativeValue !initialize minNeighborHeight = bigValue @@ -2646,7 +2645,7 @@ subroutine calc_waterPressureSmooth(block,err) integer, dimension(:), pointer :: nEdgesOnCell integer, pointer :: nTimesSmooth integer, pointer :: nCells - integer :: iCell, jCell + integer :: iCell, jEdge integer :: iNeighbor integer :: iter @@ -2677,8 +2676,8 @@ subroutine calc_waterPressureSmooth(block,err) totalPressure = pressureField(iCell)*areaCell(iCell) totalArea = areaCell(iCell) - do jCell = 1, nEdgesOnCell(iCell) - iNeighbor = cellsOnCell(jCell,iCell) + do jEdge = 1, nEdgesOnCell(iCell) + iNeighbor = cellsOnCell(jEdge,iCell) if ((li_mask_is_grounded_ice(cellMask(iNeighbor)))) then @@ -2690,13 +2689,11 @@ subroutine calc_waterPressureSmooth(block,err) waterPressureSmooth(iCell) = totalPressure / totalArea !area-weighted average pressure endif + end do + pressureField = waterPressureSmooth end do - - pressureField = waterPressureSmooth - - end do - - deallocate(pressureField) + + deallocate(pressureField) end subroutine calc_waterPressureSmooth end module li_subglacial_hydro From b352169bf19a940ffce621608505249c0a6f4340 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Wed, 22 May 2024 14:07:20 -0600 Subject: [PATCH 196/388] PR Cleanup #2 Addresses minor cleaning edits following second round of review --- .../src/Registry_subglacial_hydro.xml | 2 -- .../mode_forward/mpas_li_subglacial_hydro.F | 25 +++++-------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index 87af56eee82..fdc4cd0b387 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -152,8 +152,6 @@ - domain % blocklist do while (associated(block)) - call mpas_pool_get_subpool(block % structs, 'mesh', meshPool) call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) call mpas_pool_get_subpool(block % structs, 'geometry', geometryPool) - call mpas_pool_get_subpool(block % structs, 'velocity', velocityPool) call mpas_pool_get_array(hydroPool, 'waterPressure', waterPressure) - call mpas_pool_get_array(hydroPool, 'deltatSGH', deltatSGH) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) waterPressure = max(0.0_RKIND, waterPressure) @@ -225,7 +222,7 @@ subroutine li_SGH_init(domain, err) block => block % next end do - !updates halos for waterPressure + !updates halos for waterPressureSmooth call mpas_timer_start("halo updates") call mpas_dmpar_field_halo_exch(domain, 'waterPressureSmooth') call mpas_timer_stop("halo updates") @@ -661,7 +658,7 @@ subroutine li_SGH_solve(domain, err) call calc_pressure(block, err_tmp) err = ior(err, err_tmp) - call calc_waterPressureSmooth(block, err_tmp) !adjust ice thickness along boundaries + call calc_waterPressureSmooth(block, err_tmp) !compute smoothed version of waterPressure err = ior(err,err_tmp) block => block % next @@ -830,7 +827,6 @@ subroutine calc_edge_quantities(block, err) integer, dimension(:), pointer :: edgeMask integer, dimension(:,:), pointer :: cellsOnEdge integer, dimension(:,:), pointer :: edgesOnCell - integer, dimension(:,:), pointer :: cellsOnCell integer, dimension(:,:), pointer :: verticesOnEdge integer, dimension(:,:), pointer :: baryCellsOnVertex real (kind=RKIND), dimension(:,:), pointer :: baryWeightsOnVertex @@ -850,10 +846,6 @@ subroutine calc_edge_quantities(block, err) real (kind=RKIND) :: velSign integer :: numGroundedCells integer :: err_tmp - integer :: isMarineMargin - integer :: edgeNum - integer :: iNeighbor - integer :: numCells err = 0 err_tmp = 0 @@ -891,7 +883,6 @@ subroutine calc_edge_quantities(block, err) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(meshPool, 'cellsOnEdge', cellsOnEdge) call mpas_pool_get_array(meshPool, 'edgesOnCell', edgesOnCell) - call mpas_pool_get_array(meshPool, 'cellsOnCell', cellsOnCell) call mpas_pool_get_array(meshPool, 'edgeSignOnCell', edgeSignOnCell) call mpas_pool_get_array(hydroPool, 'hydropotentialBaseSlopeTangent', hydropotentialBaseSlopeTangent) call mpas_pool_get_array(hydroPool, 'hydropotentialSlopeTangent', hydropotentialSlopeTangent) @@ -2215,7 +2206,7 @@ subroutine ocean_connection_N(domain) type (mpas_pool_type), pointer :: geometryPool real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: effectivePressure - real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro + real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), pointer :: rhoi, rhoo ! Calculate N assuming perfect ocean connection @@ -2229,9 +2220,9 @@ subroutine ocean_connection_N(domain) call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure) - call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) + call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', thickness) - effectivePressure = rhoi * gravity * iceThicknessHydro - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography) + effectivePressure = rhoi * gravity * thickness - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography) effectivePressure = max(effectivePressure, 0.0_RKIND) ! This is just to zero out N in the open ocean to avoid confusion block => block % next @@ -2398,7 +2389,6 @@ subroutine calc_iceThicknessHydro(block, err) real (kind=RKIND), dimension(:), pointer :: thickness real (kind=RKIND), dimension(:), pointer :: bedTopography real (kind=RKIND), dimension(:), pointer :: iceThicknessHydro - real (kind=RKIND), dimension(:), pointer :: upperSurfaceHydro real (kind=RKIND), dimension(:), pointer :: upperSurface integer, dimension(:,:), pointer :: cellsOnCell integer, dimension(:), pointer :: cellMask @@ -2427,7 +2417,6 @@ subroutine calc_iceThicknessHydro(block, err) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(geometryPool, 'cellMask', cellMask) call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', iceThicknessHydro) - call mpas_pool_get_array(hydroPool, 'upperSurfaceHydro', upperSurfaceHydro) call mpas_pool_get_array(geometryPool, 'upperSurface', upperSurface) call mpas_pool_get_array(meshPool, 'nEdgesOnCell', nEdgesOnCell) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) @@ -2499,8 +2488,6 @@ subroutine calc_iceThicknessHydro(block, err) enddo endif - upperSurfaceHydro = iceThicknessHydro + bedTopography - end subroutine calc_iceThicknessHydro !*********************************************************************** @@ -2679,7 +2666,7 @@ subroutine calc_waterPressureSmooth(block,err) do jEdge = 1, nEdgesOnCell(iCell) iNeighbor = cellsOnCell(jEdge,iCell) - if ((li_mask_is_grounded_ice(cellMask(iNeighbor)))) then + if ((li_mask_is_grounded_ice(cellMask(iNeighbor)))) then !only include GROUNDED neighboring cells in smoothing totalPressure = totalPressure + pressureField(iNeighbor)*areaCell(iNeighbor) From b8acaed83043cbb59d657635a5daa983a91c4efb Mon Sep 17 00:00:00 2001 From: Trey White Date: Thu, 23 May 2024 12:34:48 -0400 Subject: [PATCH 197/388] Added pgrad_correction settings to caar_ut. Fixed support for newer Kokkos. --- .../cmake/machineFiles/frontier-bfb.cmake | 55 +++ .../homme/src/share/cxx/ExecSpaceDefs.hpp | 26 +- .../thetal_kokkos_ut/caar_interface.F90 | 8 +- .../test_execs/thetal_kokkos_ut/caar_ut.cpp | 383 +++++++++--------- 4 files changed, 275 insertions(+), 197 deletions(-) create mode 100644 components/homme/cmake/machineFiles/frontier-bfb.cmake diff --git a/components/homme/cmake/machineFiles/frontier-bfb.cmake b/components/homme/cmake/machineFiles/frontier-bfb.cmake new file mode 100644 index 00000000000..15f97742dd7 --- /dev/null +++ b/components/homme/cmake/machineFiles/frontier-bfb.cmake @@ -0,0 +1,55 @@ +SET (HOMME_MACHINE "frontier-bfb" CACHE STRING "") + +SET (HOMMEXX_CUDA_MAX_WARP_PER_TEAM "16" CACHE STRING "") + +SET (NETCDF_DIR $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} CACHE FILEPATH "") +SET (HDF5_DIR $ENV{CRAY_HDF5_PARALLEL_PREFIX} CACHE FILEPATH "") +SET (CPRNC_DIR /ccs/proj/cli115/software/frontier/cprnc CACHE FILEPATH "") + +SET(BUILD_HOMME_WITHOUT_PIOLIBRARY TRUE CACHE BOOL "") + +SET(HOMME_FIND_BLASLAPACK TRUE CACHE BOOL "") + +SET(WITH_PNETCDF FALSE CACHE FILEPATH "") + +SET(USE_QUEUING FALSE CACHE BOOL "") + +SET(BUILD_HOMME_PREQX_KOKKOS TRUE CACHE BOOL "") +SET(BUILD_HOMME_THETA_KOKKOS TRUE CACHE BOOL "") + +SET (HOMMEXX_BFB_TESTING TRUE CACHE BOOL "") + +SET(USE_TRILINOS OFF CACHE BOOL "") + +SET(HIP_BUILD TRUE CACHE BOOL "") + +SET(Kokkos_ENABLE_SERIAL ON CACHE BOOL "") +#SET(Kokkos_ENABLE_DEBUG OFF CACHE BOOL "") +SET(Kokkos_ARCH_VEGA90A ON CACHE BOOL "") +SET(Kokkos_ENABLE_OPENMP OFF CACHE BOOL "") +SET(Kokkos_ENABLE_HIP ON CACHE BOOL "") +SET(Kokkos_ENABLE_EXPLICIT_INSTANTIATION OFF CACHE BOOL "") + +SET(CMAKE_C_COMPILER "cc" CACHE STRING "") +SET(CMAKE_Fortran_COMPILER "ftn" CACHE STRING "") +SET(CMAKE_Fortran_FLAGS "--gcc-toolchain=$ENV{MEMBERWORK}/cli115/workaround" CACHE STRING "") +SET(CMAKE_CXX_COMPILER "hipcc" CACHE STRING "") + +SET(Extrae_LIBRARY "-I$ENV{CRAY_MPICH_DIR}/include -L$ENV{CRAY_MPICH_DIR}/lib -lmpi $ENV{PE_MPICH_GTL_DIR_amd_gfx90a} $ENV{PE_MPICH_GTL_LIBS_amd_gfx90a}" CACHE STRING "") + +SET(ADD_Fortran_FLAGS "--gcc-toolchain=$ENV{MEMBERWORK}/cli115/workaround -h flex_mp=intolerant -h thread0 -G2 ${Extrae_LIBRARY}" CACHE STRING "") +SET(ADD_C_FLAGS "-g -O -ffp-model=strict ${Extrae_LIBRARY}" CACHE STRING "") +SET(ADD_CXX_FLAGS "-g -std=c++14 -O -ffp-model=strict -munsafe-fp-atomics --offload-arch=gfx90a -fno-gpu-rdc -Wno-unused-command-line-argument -Wno-unsupported-floating-point-opt -Wno-#pragma-messages ${Extrae_LIBRARY}" CACHE STRING "") +SET(ADD_LINKER_FLAGS "-g -O ${Extrae_LIBRARY}" CACHE STRING "") + + +set (ENABLE_OPENMP OFF CACHE BOOL "") +set (ENABLE_COLUMN_OPENMP OFF CACHE BOOL "") +set (ENABLE_HORIZ_OPENMP OFF CACHE BOOL "") + +set (HOMME_TESTING_PROFILE "short" CACHE STRING "") +SET (BUILD_HOMME_THETA_KOKKOS TRUE CACHE BOOL "") + +set (USE_NUM_PROCS 8 CACHE STRING "") + +SET (USE_MPI_OPTIONS "-c7 --gpu-bind=closest --gpus-per-task=1" CACHE FILEPATH "") diff --git a/components/homme/src/share/cxx/ExecSpaceDefs.hpp b/components/homme/src/share/cxx/ExecSpaceDefs.hpp index 42be0b6f71e..cd6649c7ab2 100644 --- a/components/homme/src/share/cxx/ExecSpaceDefs.hpp +++ b/components/homme/src/share/cxx/ExecSpaceDefs.hpp @@ -8,6 +8,9 @@ #define HOMMEXX_EXEC_SPACE_DEFS_HPP #include +#ifdef HOMMEXX_BFB_TESTING +#include +#endif #include @@ -343,7 +346,7 @@ struct Dispatch { }); // Broadcast result to all threads by doing sum of one thread's // non-0 value and the rest of the 0s. - Kokkos::Impl::CudaTeamMember::vector_reduce( + Kokkos::TeamPolicy::member_type::vector_reduce( Kokkos::Sum(local_tmp)); result = local_tmp; #else @@ -371,6 +374,21 @@ struct Dispatch { lambda, result); } +#ifdef HOMMEXX_BFB_TESTING + // Template for getting the type of the second argument to a lambda + private: + template struct arg2; + + template + struct arg2 + { + using type = typename std::remove_reference< + typename std::tuple_element<1,std::tuple>::type + >::type; + }; + public: +#endif + template static KOKKOS_FORCEINLINE_FUNCTION void parallel_scan ( @@ -383,11 +401,7 @@ struct Dispatch { // serialize parallel scans. // Detect the value type - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Lambda >::value_type ; + using value_type = typename arg2::type; // All threads init result. value_type accumulator = Kokkos::reduction_identity::sum(); diff --git a/components/homme/test_execs/thetal_kokkos_ut/caar_interface.F90 b/components/homme/test_execs/thetal_kokkos_ut/caar_interface.F90 index 346dc1a23d3..6077cca921e 100644 --- a/components/homme/test_execs/thetal_kokkos_ut/caar_interface.F90 +++ b/components/homme/test_execs/thetal_kokkos_ut/caar_interface.F90 @@ -32,11 +32,12 @@ subroutine init_caar_f90 (ne, hyai, hybi, hyam, hybm, dvv, mp, ps0) bind(c) end subroutine init_caar_f90 subroutine run_caar_f90 (nm1, n0, np1, dt, eta_ave_w, scale1, scale2, scale3, & - hydrostatic, adv_conservative, rsplit_in, & + hydrostatic, adv_conservative, rsplit_in, pgrad, & dp_ptr, vtheta_dp_ptr, w_i_ptr, phi_i_ptr, v_ptr, & vn0_ptr, etadot_dpdn_ptr, omega_p_ptr) bind(c) use iso_c_binding, only: c_ptr, c_f_pointer, c_int, c_bool - use control_mod, only: theta_hydrostatic_mode, theta_advect_form, rsplit + use control_mod, only: pgrad_correction, rsplit + use control_mod, only: theta_hydrostatic_mode, theta_advect_form use dimensions_mod, only: nelemd, nlev, nlevp, np use prim_advance_mod, only: compute_andor_apply_rhs use thetal_test_interface, only: deriv, hvcoord @@ -46,7 +47,7 @@ subroutine run_caar_f90 (nm1, n0, np1, dt, eta_ave_w, scale1, scale2, scale3, & ! Input(s) ! real (kind=real_kind), intent(in) :: dt, eta_ave_w, scale1, scale2, scale3 - integer (kind=c_int), intent(in) :: nm1, n0, np1, rsplit_in + integer (kind=c_int), intent(in) :: nm1, n0, np1, pgrad, rsplit_in logical (kind=c_bool), intent(in) :: hydrostatic, adv_conservative type (c_ptr), intent(in) :: dp_ptr, vtheta_dp_ptr, w_i_ptr, phi_i_ptr, v_ptr type (c_ptr), intent(in) :: vn0_ptr, etadot_dpdn_ptr, omega_p_ptr @@ -87,6 +88,7 @@ subroutine run_caar_f90 (nm1, n0, np1, dt, eta_ave_w, scale1, scale2, scale3, & enddo ! set control variables + pgrad_correction = pgrad rsplit = rsplit_in theta_hydrostatic_mode = hydrostatic if (adv_conservative) then diff --git a/components/homme/test_execs/thetal_kokkos_ut/caar_ut.cpp b/components/homme/test_execs/thetal_kokkos_ut/caar_ut.cpp index c2022b35c04..7089e1187f3 100644 --- a/components/homme/test_execs/thetal_kokkos_ut/caar_ut.cpp +++ b/components/homme/test_execs/thetal_kokkos_ut/caar_ut.cpp @@ -30,7 +30,8 @@ void init_geo_views_f90 (Real*& d_ptr,Real*& dinv_ptr, void run_caar_f90 (const int& nm1, const int& n0, const int& np1, const Real& dt, const Real& eta_ave_w, const Real& scale1, const Real& scale2, const Real& scale3, - const bool& hydrostatic, const bool& adv_conservative, const int& rsplit, + const bool& hydrostatic, const bool& adv_conservative, + const int& rsplit, const int& pgrad, Real*& dp_ptr, Real*& vtheta_dp_ptr, Real*& w_i_ptr, Real*& phi_i_ptr, Real*& v_ptr, Real*& vn0_ptr, Real*& etadot_dpdn_ptr, Real*& omega_p_ptr); @@ -232,207 +233,213 @@ TEST_CASE("caar", "caar_testing") { if (comm.root()) { std::cout << " -> rsplit = " << rsplit << "\n"; } - // Set the parameters - params.theta_hydrostatic_mode = hydrostatic; - params.theta_adv_form = adv_form; - params.rsplit = rsplit; - - // Generate RK stage data - Real dt = RPDF(1.0,10.0)(engine); - Real eta_ave_w = RPDF(0.1,1.0)(engine); - Real scale1 = RPDF(1.0,2.0)(engine); - Real scale2 = RPDF(1.0,2.0)(engine); - Real scale3 = RPDF(1.0,2.0)(engine); - - int np1 = IPDF(0,2)(engine); - - // Sync scalars across ranks (only np1 is *really* necessary, but might as well...) - auto mpi_comm = Context::singleton().get().mpi_comm(); - MPI_Bcast(&dt,1,MPI_DOUBLE,0,mpi_comm); - MPI_Bcast(&scale1,1,MPI_DOUBLE,0,mpi_comm); - MPI_Bcast(&scale2,1,MPI_DOUBLE,0,mpi_comm); - MPI_Bcast(&scale3,1,MPI_DOUBLE,0,mpi_comm); - MPI_Bcast(&eta_ave_w,1,MPI_DOUBLE,0,mpi_comm); - MPI_Bcast(&np1,1,MPI_INT,0,mpi_comm); - - const int n0 = (np1+1)%3; - const int nm1 = (np1+2)%3; - - RKStageData data (nm1, n0, np1, 0, dt, eta_ave_w, scale1, scale2, scale3); - - // Randomize state/derived - elems.m_state.randomize(seed,max_pressure,hvcoord.ps0,hvcoord.hybrid_ai0,geo.m_phis); - elems.m_derived.randomize(seed,dp3d_min(elems.m_state.m_dp3d)); - - // Copy initial values to f90 - sync_to_host(elems.m_state.m_dp3d, dp3d_f90); - sync_to_host(elems.m_state.m_vtheta_dp, vtheta_dp_f90); - sync_to_host(elems.m_state.m_w_i, w_i_f90); - sync_to_host(elems.m_state.m_phinh_i, phinh_i_f90); - sync_to_host(elems.m_state.m_v, v_f90); - - sync_to_host<2>(elems.m_derived.m_vn0, vn0_f90); - sync_to_host(elems.m_derived.m_eta_dot_dpdn, eta_dot_dpdn_f90); - sync_to_host(elems.m_derived.m_omega_p, omega_p_f90); - - // Create the Caar functor - CaarFunctorImpl caar(elems,tracers,ref_FE,hvcoord,sphop,params); - FunctorsBuffersManager fbm; - fbm.request_size( caar.requested_buffer_size() ); - fbm.request_size(limiter.requested_buffer_size()); - fbm.allocate(); - caar.init_buffers(fbm); - limiter.init_buffers(fbm); - caar.init_boundary_exchanges(c.get_ptr()); - - // Run cxx - caar.run(data); - - auto dp3d_ptr = dp3d_f90.data(); - auto vtheta_dp_ptr = vtheta_dp_f90.data(); - auto w_i_ptr = w_i_f90.data(); - auto phinh_i_ptr = phinh_i_f90.data(); - auto v_ptr = v_f90.data(); - auto vn0_ptr = vn0_f90.data(); - auto eta_dot_dpdn_ptr = eta_dot_dpdn_f90.data(); - auto omega_p_ptr = omega_p_f90.data(); - run_caar_f90 (nm1+1, n0+1, np1+1, dt, eta_ave_w, scale1, scale2, scale3, - hydrostatic, adv_form==AdvectionForm::Conservative, rsplit, - dp3d_ptr, vtheta_dp_ptr, w_i_ptr, - phinh_i_ptr, v_ptr, - vn0_ptr, eta_dot_dpdn_ptr, omega_p_ptr); - - // Compare answers - auto h_dp3d = Kokkos::create_mirror_view(elems.m_state.m_dp3d); - auto h_vtheta_dp = Kokkos::create_mirror_view(elems.m_state.m_vtheta_dp); - auto h_w_i = Kokkos::create_mirror_view(elems.m_state.m_w_i); - auto h_phinh_i = Kokkos::create_mirror_view(elems.m_state.m_phinh_i); - auto h_v = Kokkos::create_mirror_view(elems.m_state.m_v); - - auto h_vn0 = Kokkos::create_mirror_view(elems.m_derived.m_vn0); - auto h_eta_dot_dpdn = Kokkos::create_mirror_view(elems.m_derived.m_eta_dot_dpdn); - auto h_omega_p = Kokkos::create_mirror_view(elems.m_derived.m_omega_p); - - Kokkos::deep_copy(h_dp3d , elems.m_state.m_dp3d); - Kokkos::deep_copy(h_vtheta_dp, elems.m_state.m_vtheta_dp); - Kokkos::deep_copy(h_w_i , elems.m_state.m_w_i); - Kokkos::deep_copy(h_phinh_i , elems.m_state.m_phinh_i); - Kokkos::deep_copy(h_v , elems.m_state.m_v); - - Kokkos::deep_copy(h_vn0 , elems.m_derived.m_vn0); - Kokkos::deep_copy(h_eta_dot_dpdn, elems.m_derived.m_eta_dot_dpdn); - Kokkos::deep_copy(h_omega_p , elems.m_derived.m_omega_p); - - for (int ie=0; ie pgrad_correction = " << pgrad << "\n"; + } + // Set the parameters + params.theta_hydrostatic_mode = hydrostatic; + params.theta_adv_form = adv_form; + params.rsplit = rsplit; + params.pgrad_correction = (pgrad != 0); + + // Generate RK stage data + Real dt = RPDF(1.0,10.0)(engine); + Real eta_ave_w = RPDF(0.1,1.0)(engine); + Real scale1 = RPDF(1.0,2.0)(engine); + Real scale2 = RPDF(1.0,2.0)(engine); + Real scale3 = RPDF(1.0,2.0)(engine); + + int np1 = IPDF(0,2)(engine); + + // Sync scalars across ranks (only np1 is *really* necessary, but might as well...) + auto mpi_comm = Context::singleton().get().mpi_comm(); + MPI_Bcast(&dt,1,MPI_DOUBLE,0,mpi_comm); + MPI_Bcast(&scale1,1,MPI_DOUBLE,0,mpi_comm); + MPI_Bcast(&scale2,1,MPI_DOUBLE,0,mpi_comm); + MPI_Bcast(&scale3,1,MPI_DOUBLE,0,mpi_comm); + MPI_Bcast(&eta_ave_w,1,MPI_DOUBLE,0,mpi_comm); + MPI_Bcast(&np1,1,MPI_INT,0,mpi_comm); + + const int n0 = (np1+1)%3; + const int nm1 = (np1+2)%3; + + RKStageData data (nm1, n0, np1, 0, dt, eta_ave_w, scale1, scale2, scale3); + + // Randomize state/derived + elems.m_state.randomize(seed,max_pressure,hvcoord.ps0,hvcoord.hybrid_ai0,geo.m_phis); + elems.m_derived.randomize(seed,dp3d_min(elems.m_state.m_dp3d)); + + // Copy initial values to f90 + sync_to_host(elems.m_state.m_dp3d, dp3d_f90); + sync_to_host(elems.m_state.m_vtheta_dp, vtheta_dp_f90); + sync_to_host(elems.m_state.m_w_i, w_i_f90); + sync_to_host(elems.m_state.m_phinh_i, phinh_i_f90); + sync_to_host(elems.m_state.m_v, v_f90); + + sync_to_host<2>(elems.m_derived.m_vn0, vn0_f90); + sync_to_host(elems.m_derived.m_eta_dot_dpdn, eta_dot_dpdn_f90); + sync_to_host(elems.m_derived.m_omega_p, omega_p_f90); + + // Create the Caar functor + CaarFunctorImpl caar(elems,tracers,ref_FE,hvcoord,sphop,params); + FunctorsBuffersManager fbm; + fbm.request_size( caar.requested_buffer_size() ); + fbm.request_size(limiter.requested_buffer_size()); + fbm.allocate(); + caar.init_buffers(fbm); + limiter.init_buffers(fbm); + caar.init_boundary_exchanges(c.get_ptr()); + + // Run cxx + caar.run(data); + + auto dp3d_ptr = dp3d_f90.data(); + auto vtheta_dp_ptr = vtheta_dp_f90.data(); + auto w_i_ptr = w_i_f90.data(); + auto phinh_i_ptr = phinh_i_f90.data(); + auto v_ptr = v_f90.data(); + auto vn0_ptr = vn0_f90.data(); + auto eta_dot_dpdn_ptr = eta_dot_dpdn_f90.data(); + auto omega_p_ptr = omega_p_f90.data(); + run_caar_f90 (nm1+1, n0+1, np1+1, dt, eta_ave_w, scale1, scale2, scale3, + hydrostatic, adv_form==AdvectionForm::Conservative, rsplit, + pgrad, dp3d_ptr, vtheta_dp_ptr, w_i_ptr, + phinh_i_ptr, v_ptr, + vn0_ptr, eta_dot_dpdn_ptr, omega_p_ptr); + + // Compare answers + auto h_dp3d = Kokkos::create_mirror_view(elems.m_state.m_dp3d); + auto h_vtheta_dp = Kokkos::create_mirror_view(elems.m_state.m_vtheta_dp); + auto h_w_i = Kokkos::create_mirror_view(elems.m_state.m_w_i); + auto h_phinh_i = Kokkos::create_mirror_view(elems.m_state.m_phinh_i); + auto h_v = Kokkos::create_mirror_view(elems.m_state.m_v); + + auto h_vn0 = Kokkos::create_mirror_view(elems.m_derived.m_vn0); + auto h_eta_dot_dpdn = Kokkos::create_mirror_view(elems.m_derived.m_eta_dot_dpdn); + auto h_omega_p = Kokkos::create_mirror_view(elems.m_derived.m_omega_p); + + Kokkos::deep_copy(h_dp3d , elems.m_state.m_dp3d); + Kokkos::deep_copy(h_vtheta_dp, elems.m_state.m_vtheta_dp); + Kokkos::deep_copy(h_w_i , elems.m_state.m_w_i); + Kokkos::deep_copy(h_phinh_i , elems.m_state.m_phinh_i); + Kokkos::deep_copy(h_v , elems.m_state.m_v); + + Kokkos::deep_copy(h_vn0 , elems.m_derived.m_vn0); + Kokkos::deep_copy(h_eta_dot_dpdn, elems.m_derived.m_eta_dot_dpdn); + Kokkos::deep_copy(h_omega_p , elems.m_derived.m_omega_p); + + for (int ie=0; ie Date: Thu, 23 May 2024 14:49:34 -0500 Subject: [PATCH 198/388] Add atm dust forcing and iron solubility map Adds 2 namelist fields: config_use_atm_dust_file - true, use monthly dust climatology config_use_iron_solubility_file -- true, use dust-iron solubility map from file (in icepack: use_atm_dust_sol = .not.config_use_iron_solubility_file) New fields track atmospheric wet and dry dust separately from the coupler to compute the iron contribution. Fraction of iron in dust is also generalized and read from a file. Dust/iron file is identical to the one used by mpas-o. Corrects some units in Registry. BFB with new namelist parameters = false and for all runs without zaerosols or without iron. --- components/mpas-seaice/bld/build-namelist | 2 + .../mpas-seaice/bld/build-namelist-section | 2 + .../namelist_defaults_mpassi.xml | 2 + .../namelist_definition_mpassi.xml | 16 + components/mpas-seaice/cime_config/buildnml | 9 +- components/mpas-seaice/driver/ice_comp_mct.F | 83 ++++- components/mpas-seaice/src/Registry.xml | 102 ++++-- .../mpas_seaice_core_interface.F | 16 +- .../src/shared/mpas_seaice_constants.F | 6 +- .../src/shared/mpas_seaice_forcing.F | 295 +++++++++++++++++- .../src/shared/mpas_seaice_icepack.F | 54 +++- 11 files changed, 537 insertions(+), 50 deletions(-) diff --git a/components/mpas-seaice/bld/build-namelist b/components/mpas-seaice/bld/build-namelist index d8bfcaa68c0..b5faa4ceeb2 100755 --- a/components/mpas-seaice/bld/build-namelist +++ b/components/mpas-seaice/bld/build-namelist @@ -696,6 +696,8 @@ add_default($nl, 'config_use_chlorophyll'); add_default($nl, 'config_use_macromolecules'); add_default($nl, 'config_use_modal_aerosols'); add_default($nl, 'config_use_zaerosols'); +add_default($nl, 'config_use_atm_dust_file'); +add_default($nl, 'config_use_iron_solubility_file'); add_default($nl, 'config_skeletal_bgc_flux_type'); add_default($nl, 'config_scale_initial_vertical_bgc'); add_default($nl, 'config_biogrid_bottom_molecular_sublayer'); diff --git a/components/mpas-seaice/bld/build-namelist-section b/components/mpas-seaice/bld/build-namelist-section index 8b6a06dd674..d2866ee4c81 100644 --- a/components/mpas-seaice/bld/build-namelist-section +++ b/components/mpas-seaice/bld/build-namelist-section @@ -213,6 +213,8 @@ add_default($nl, 'config_use_DON'); add_default($nl, 'config_use_iron'); add_default($nl, 'config_use_modal_aerosols'); add_default($nl, 'config_use_zaerosols'); +add_default($nl, 'config_use_atm_dust_file'); +add_default($nl, 'config_use_iron_solubility_file'); add_default($nl, 'config_skeletal_bgc_flux_type'); add_default($nl, 'config_scale_initial_vertical_bgc'); add_default($nl, 'config_biogrid_bottom_molecular_sublayer'); diff --git a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml index f4f9bfa1ec3..1ac5bfe8a04 100644 --- a/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml +++ b/components/mpas-seaice/bld/namelist_files/namelist_defaults_mpassi.xml @@ -239,6 +239,8 @@ false false false +false +false 'Jin2006' false 0.006 diff --git a/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml b/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml index 5f56625f8d9..548004a78dc 100644 --- a/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml +++ b/components/mpas-seaice/bld/namelist_files/namelist_definition_mpassi.xml @@ -1115,6 +1115,22 @@ Valid values: true or false Default: Defined in namelist_defaults.xml + +Read atmospheric dust fluxes from a file + +Valid values: true or false +Default: Defined in namelist_defaults.xml + + + +Read atmospheric dust-iron solubility from a file + +Valid values: true or false +Default: Defined in namelist_defaults.xml + + Determines the ocean-ice fluxes of biogeochemistry for the bottom1-layer model: in Jin2006, the piston velocity is a function of ice growth/melt rate, in default, the piston velocity is constant diff --git a/components/mpas-seaice/cime_config/buildnml b/components/mpas-seaice/cime_config/buildnml index e29def8a31f..5aa44cf06b9 100755 --- a/components/mpas-seaice/cime_config/buildnml +++ b/components/mpas-seaice/cime_config/buildnml @@ -587,7 +587,14 @@ def buildnml(case, caseroot, compname): lines.append('') + lines.append('') + lines.append('') lines.append('') diff --git a/components/mpas-seaice/driver/ice_comp_mct.F b/components/mpas-seaice/driver/ice_comp_mct.F index 1dac3749056..5c1bc715518 100644 --- a/components/mpas-seaice/driver/ice_comp_mct.F +++ b/components/mpas-seaice/driver/ice_comp_mct.F @@ -1222,7 +1222,6 @@ subroutine ice_run_mct( EClock, cdata_i, x2i_i, i2x_i)!{{{ #endif call ice_import_moab(Eclock) #endif - ! Post coupling calls block => domain % blocklist @@ -1999,7 +1998,9 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ oceanZAerosolConcField, & atmosAerosolFluxField, & atmosBlackCarbonFluxField, & - atmosDustFluxField + atmosDustFluxField, & + atmosWetDustFluxField, & + atmosDryDustFluxField real (kind=RKIND), dimension(:), pointer :: & seaSurfaceTemperature, & @@ -2045,7 +2046,9 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ oceanZAerosolConc, & atmosAerosolFlux, & atmosBlackCarbonFlux, & - atmosDustFlux + atmosDustFlux, & + atmosWetDustFlux, & + atmosDryDustFlux !----------------------------------------------------------------------- ! @@ -2116,6 +2119,8 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) call mpas_pool_get_array(biogeochemistry, 'atmosBlackCarbonFlux', atmosBlackCarbonFlux) call mpas_pool_get_array(biogeochemistry, 'atmosDustFlux', atmosDustFlux) + call mpas_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) + call mpas_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) endif if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then @@ -2247,6 +2252,16 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) + + atmosWetDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) + atmosWetDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) + atmosWetDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) + atmosWetDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) + + atmosDryDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) + atmosDryDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) + atmosDryDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) + atmosDryDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) else atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) atmosBlackCarbonFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) & @@ -2260,6 +2275,16 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ + x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) atmosDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) & + x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) + + atmosDryDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry1, n) + atmosDryDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry2, n) + atmosDryDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry3, n) + atmosDryDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstdry4, n) + + atmosWetDustFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet1, n) + atmosWetDustFlux(2,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet2, n) + atmosWetDustFlux(3,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet3, n) + atmosWetDustFlux(4,i) = x2i_i % rAttr(index_x2i_Faxa_dstwet4, n) endif endif ! import biogeochemistry fields, if configured @@ -2348,6 +2373,8 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ if (config_use_zaerosols) then call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosWetDustFlux", atmosWetDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosDryDustFlux", atmosDryDustFluxField) call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) endif if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then @@ -2398,6 +2425,8 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ if (config_use_zaerosols) then call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) call mpas_dmpar_exch_halo_field(atmosDustFluxField) + call mpas_dmpar_exch_halo_field(atmosDryDustFluxField) + call mpas_dmpar_exch_halo_field(atmosWetDustFluxField) call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) endif if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then @@ -3567,7 +3596,9 @@ subroutine ice_import_moab(Eclock)!{{{ oceanZAerosolConcField, & atmosAerosolFluxField, & atmosBlackCarbonFluxField, & - atmosDustFluxField + atmosDustFluxField, & + atmosWetDustFluxField, & + atmosDryDustFluxField real (kind=RKIND), dimension(:), pointer :: & seaSurfaceTemperature, & @@ -3612,7 +3643,9 @@ subroutine ice_import_moab(Eclock)!{{{ oceanZAerosolConc, & atmosAerosolFlux, & atmosBlackCarbonFlux, & - atmosDustFlux + atmosDustFlux, & + atmosWetDustFlux, & + atmosDryDustFlux character(CXX) :: tagname integer :: ierr, ent_type integer :: cur_ice_stepno @@ -3721,6 +3754,8 @@ subroutine ice_import_moab(Eclock)!{{{ if (config_use_zaerosols) then call mpas_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) call mpas_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) + call mpas_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) + call mpas_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) endif endif @@ -3737,8 +3772,8 @@ subroutine ice_import_moab(Eclock)!{{{ seaSurfaceTiltV(i) = x2i_im(n,index_x2i_So_dhdy) if (trim(config_ocean_surface_type) == "free") then ! free surface (MPAS-O) - - ! freezingMeltingPotential(i) is the ocean energy associated with frazil formation + + ! freezingMeltingPotential(i) is the ocean energy associated with frazil formation ! when it is positive and frazilMassFlux is positive. Conversely, freezingMeltingPotential(i) ! is negative when there is the melting potential in which case frazilMassFlux is zero. @@ -3747,7 +3782,7 @@ subroutine ice_import_moab(Eclock)!{{{ frazilMassFlux = x2i_im(n,index_x2i_Fioo_frazil) ! Now determine the sea ice mass associated with the frazil heat flux given when - ! freezingMeltingPotential(i) is positive. This produces a revised mass flux, given + ! freezingMeltingPotential(i) is positive. This produces a revised mass flux, given ! in frazilMassFluxRev for the given sea surface salinity. The resulting difference ! is assigned to frazilMassAdjust(i) which is exported to the ocean in the subsequent ! coupling step as a freshwater and salt flux. This step is required to balance mass @@ -3755,7 +3790,7 @@ subroutine ice_import_moab(Eclock)!{{{ call frazil_mass(freezingMeltingPotential(i), frazilMassFluxRev, seaSurfaceSalinity(i)) - frazilMassAdjust(i) = frazilMassFlux-frazilMassFluxRev + frazilMassAdjust(i) = frazilMassFlux-frazilMassFluxRev else ! non-free surface (SOM) @@ -3850,6 +3885,18 @@ subroutine ice_import_moab(Eclock)!{{{ + x2i_im(n,index_x2i_Faxa_dstdry3) atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & + x2i_im(n,index_x2i_Faxa_dstdry4) + + ! wet dust + atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) + atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) + atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) + atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) + + ! dry dust + atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) else atmosBlackCarbonFlux(1,i) = x2i_im(n,index_x2i_Faxa_bcphodry) atmosBlackCarbonFlux(2,i) = x2i_im(n,index_x2i_Faxa_bcphidry) & @@ -3863,12 +3910,24 @@ subroutine ice_import_moab(Eclock)!{{{ + x2i_im(n,index_x2i_Faxa_dstdry3) atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & + x2i_im(n,index_x2i_Faxa_dstdry4) + + ! wet dust + atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) + atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) + atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) + atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) + + ! dry dust + atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) endif endif endif end do -!----------------------------------------------------------------------- +!----------------------------------------------------------------------- ! ! unit conversions and any manipulation of coupled fields ! @@ -3946,6 +4005,8 @@ subroutine ice_import_moab(Eclock)!{{{ if (config_use_zaerosols) then call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosWetDustFlux", atmosWetDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosDryDustFlux", atmosDryDustFluxField) endif endif @@ -3995,6 +4056,8 @@ subroutine ice_import_moab(Eclock)!{{{ if (config_use_zaerosols) then call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) call mpas_dmpar_exch_halo_field(atmosDustFluxField) + call mpas_dmpar_exch_halo_field(atmosWetDustFluxField) + call mpas_dmpar_exch_halo_field(atmosDryDustFluxField) endif endif diff --git a/components/mpas-seaice/src/Registry.xml b/components/mpas-seaice/src/Registry.xml index 7a5d18c3dc5..b4ffd634bd2 100644 --- a/components/mpas-seaice/src/Registry.xml +++ b/components/mpas-seaice/src/Registry.xml @@ -889,6 +889,14 @@ description="Aerosols in the ice use the z-aerosol scheme" possible_values="true or false" icepack_name="tr_zaero" + /> + + + + + + + + + + + + + + @@ -5278,7 +5328,21 @@ /> + + @@ -5330,7 +5394,7 @@ type="real" dimensions="nZBGCTracers nCategories nCells Time" units="mmol m-2 s-1" - description="Only bio tracers used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m2/s, particulate iron in umol/m2/s, humic carbon, black carbon1 in mg/m2/s, black carbon2 in mg/m2/s, dust1 in mg/m2/s, dust2 in mg/m2/s, dust3 in mg/m2/s, dust4 in mg/m2/s" + description="Only bio tracers used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m2/s, particulate iron in umol/m2/s, humic carbon, black carbon1 in kg/m2/s, black carbon2 in kg/m2/s, dust1 in kg/m2/s, dust2 in kg/m2/s, dust3 in kg/m2/s, dust4 in kg/m2/s" icepack_name="flux_bion" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> @@ -5518,104 +5582,104 @@ \brief +!> \author Nicole Jeffery, LANL +!> \date +!> \details: reads data file for dust fluxes and dust-iron solubility +!> +! +!----------------------------------------------------------------------- + + subroutine atmospheric_aerosols_forcing(& + streamManager, & + domain, & + simulationClock, & + firstTimeStep) + + type (MPAS_streamManager_type), intent(inout) :: streamManager + + type (domain_type) :: domain + + type (MPAS_clock_type) :: simulationClock + + logical, intent(in) :: & + firstTimeStep + + type (block_type), pointer :: block + + real(kind=RKIND), pointer :: & + config_dt + + ! configurations + call mpas_pool_get_config(domain % configs, 'config_dt', config_dt) + + call MPAS_forcing_get_forcing(seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', streamManager, config_dt) + + block => domain % blocklist + do while (associated(block)) + + ! convert the input forcing variables to the coupling variables + call prepare_atmospheric_dust_coupling_variables(block) + + block => block % next + end do + + end subroutine atmospheric_aerosols_forcing + !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! ! prepare_atmospheric_coupling_variables_CORE @@ -1044,6 +1117,74 @@ subroutine prepare_atmospheric_coupling_variables_ISPOL(block) end subroutine prepare_atmospheric_coupling_variables_ISPOL +!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +! +! prepare_atmospheric_dust_coupling_variables +! +!> \brief +!> \author Nicole Jeffery, LANL +!> \date +!> \details +!> Defines the atm flux fields for dust if reading from a file +! +!----------------------------------------------------------------------- + + subroutine prepare_atmospheric_dust_coupling_variables(block) + + type (block_type), pointer :: block + + type (mpas_pool_type), pointer :: & + mesh, & + atmosCoupling, & + atmosForcing, & + biogeochemistry + + real(kind=RKIND), dimension(:,:), pointer :: & + atmosDustFlux, & + atmosWetDustFlux, & + atmosDryDustFlux + + real(kind=RKIND), dimension(:), pointer :: & + dust_FLUZ_WET, & + dust_FLUZ_DRY + + integer, pointer :: & + nCellsSolve, & + maxBCType, & + nzAerosols + + integer :: & + iCell, & + iBioTracers, & + nDust + + call MPAS_pool_get_subpool(block % structs, "mesh", mesh) + call MPAS_pool_get_subpool(block % structs, "atmos_forcing", atmosForcing) + + call MPAS_pool_get_dimension(mesh, "nCellsSolve", nCellsSolve) + + ! zaerosols + + call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry) + call MPAS_pool_get_dimension(mesh, "maxBCType", maxBCType) + call MPAS_pool_get_dimension(mesh, "nzAerosols", nzAerosols) + call MPAS_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) + call MPAS_pool_get_array(atmosForcing, "dust_FLUZ_WET", dust_FLUZ_WET) + call MPAS_pool_get_array(atmosForcing, "dust_FLUZ_DRY", dust_FLUZ_DRY) + + nDust = MAX(1,nzAerosols - maxBCType) + do iCell = 1, nCellsSolve + do iBioTracers = maxBCType + 1, nzAerosols + atmosDustFlux(iBioTracers,iCell) = (dust_FLUZ_WET(iCell) + dust_FLUZ_DRY(iCell))/nDust + atmosWetDustFlux(iBioTracers,iCell) = dust_FLUZ_WET(iCell)/nDust + atmosDryDustFlux(iBiotracers,iCell) = dust_FLUZ_DRY(iCell)/nDust + enddo + end do + + end subroutine prepare_atmospheric_dust_coupling_variables + !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! ! post_atmospheric_coupling @@ -1675,6 +1816,129 @@ subroutine init_oceanic_bgc_forcing(domain) end subroutine init_oceanic_bgc_forcing +!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +! +! init_atm_iron_bgc_forcing +! +!> \brief +!> \author Nicole Jeffery, LANL +!> \date 5th April 2024 +!> \details +!> Uses monthly iron solubility maps from CAM6-MIMI (Yan Feng) +! to convert dust to dissolved iron for bgc. +!----------------------------------------------------------------------- + + subroutine init_atm_iron_bgc_forcing(domain, clock) + + type (domain_type) :: domain + + type (MPAS_Clock_type) :: clock + + logical, pointer :: & + config_do_restart + + character(len=strKIND) :: & + forcingIntervalMonthly, & + forcingReferenceTimeMonthly + + type (MPAS_Time_Type) :: currTime + character(len=strKIND) :: timeStamp + integer :: ierr + ! get forcing configuration options + call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart) + + ! create the dust iron solubility forcing group + + currTime = mpas_get_clock_time(clock, MPAS_NOW, ierr) + call mpas_get_time(curr_time=currTime, dateTimeString=timeStamp, ierr=ierr) + timeStamp = '0000'//trim(timeStamp(5:)) + + call MPAS_forcing_init_group(& + seaiceForcingGroups, & + "seaice_atm_bgc_forcing_monthly", & + domain, & + '0000-01-01_00:00:00', & + '0000-01-01_00:00:00', & + '0001-00-00_00:00:00', & + config_do_restart) + + forcingIntervalMonthly = "00-01-00_00:00:00" + forcingReferenceTimeMonthly = "0001-01-15_00:00:00" + + ! iron solubility fraction of wet dust iron + call MPAS_forcing_init_field(& + domain % streamManager, & + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + 'IRON_Zolubility_wet', & + 'DustIronMonthlyForcing', & + 'atmos_forcing', & + 'IRON_Zolubility_wet', & + 'linear', & + forcingReferenceTimeMonthly, & + forcingIntervalMonthly) + + ! iron solubility fraction of dry dust iron + call MPAS_forcing_init_field(& + domain % streamManager, & + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + 'IRON_Zolubility_dry', & + 'DustIronMonthlyForcing', & + 'atmos_forcing', & + 'IRON_Zolubility_dry', & + 'linear', & + forcingReferenceTimeMonthly, & + forcingIntervalMonthly) + + ! atmospheric wet dust flux + call MPAS_forcing_init_field(& + domain % streamManager, & + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + 'dust_FLUZ_WET', & + 'DustIronMonthlyForcing', & + 'atmos_forcing', & + 'dust_FLUZ_WET', & + 'linear', & + forcingReferenceTimeMonthly, & + forcingIntervalMonthly) + + ! atmospheric dry dust flux + call MPAS_forcing_init_field(& + domain % streamManager, & + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + 'dust_FLUZ_DRY', & + 'DustIronMonthlyForcing', & + 'atmos_forcing', & + 'dust_FLUZ_DRY', & + 'linear', & + forcingReferenceTimeMonthly, & + forcingIntervalMonthly) + + ! iron fraction in dust + call MPAS_forcing_init_field(& + domain % streamManager, & + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + 'IRON_in_duzt_fraction', & + 'DustIronMonthlyForcing', & + 'atmos_forcing', & + 'IRON_in_duzt_fraction', & + 'linear', & + forcingReferenceTimeMonthly, & + forcingIntervalMonthly) + + call MPAS_forcing_init_field_data(& + seaiceForcingGroups, & + 'seaice_atm_bgc_forcing_monthly', & + domain % streamManager, & + config_do_restart, & + .false.) + + end subroutine init_atm_iron_bgc_forcing + !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! ! init_oceanic_forcing_ncar @@ -3177,10 +3441,12 @@ subroutine reset_atmospheric_coupler_fluxes(domain) real(kind=RKIND), dimension(:,:), pointer :: & atmosBioFluxes, & atmosBlackCarbonFlux, & - atmosDustFlux + atmosDustFlux, & + atmosWetDustFlux, & + atmosDryDustFlux logical, pointer :: & - config_use_column_biogeochemistry + config_use_zaerosols block => domain % blocklist do while (associated(block)) @@ -3219,20 +3485,24 @@ subroutine reset_atmospheric_coupler_fluxes(domain) atmosReferenceTemperature2m = 0.0_RKIND atmosReferenceHumidity2m = 0.0_RKIND - ! biogeochemistry - call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + ! zaerosols + call MPAS_pool_get_config(block % configs, "config_use_zaerosols", config_use_zaerosols) - if (config_use_column_biogeochemistry) then + if (config_use_zaerosols) then call MPAS_pool_get_subpool(block % structs, "biogeochemistry", biogeochemistry) call MPAS_pool_get_array(biogeochemistry, "atmosBioFluxes", atmosBioFluxes) call MPAS_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) atmosBioFluxes = 0.0_RKIND atmosBlackCarbonFlux = 0.0_RKIND atmosDustFlux = 0.0_RKIND + atmosWetDustFlux = 0.0_RKIND + atmosDryDustFlux = 0.0_RKIND endif @@ -3396,16 +3666,21 @@ subroutine seaice_forcing_write_restart_times(domain) config_use_forcing, & config_use_prescribed_ice, & config_use_prescribed_ice_forcing, & - config_use_data_icebergs + config_use_data_icebergs, & + config_use_atm_dust_file, & + config_use_iron_solubility_file call MPAS_pool_get_config(domain % configs, "config_use_forcing", config_use_forcing) call MPAS_pool_get_config(domain % configs, "config_use_prescribed_ice", config_use_prescribed_ice) call MPAS_pool_get_config(domain % configs, "config_use_prescribed_ice_forcing", config_use_prescribed_ice_forcing) call MPAS_pool_get_config(domain % configs, "config_use_data_icebergs", config_use_data_icebergs) + call MPAS_pool_get_config(domain % configs, "config_use_atm_dust_file", config_use_atm_dust_file) + call MPAS_pool_get_config(domain % configs, "config_use_iron_solubility_file", config_use_iron_solubility_file) if (config_use_forcing .or. & (config_use_prescribed_ice .and. config_use_prescribed_ice_forcing) .or. & - config_use_data_icebergs) then + config_use_data_icebergs .or. & + config_use_atm_dust_file .or. config_use_iron_solubility_file) then call MPAS_forcing_write_restart_times(seaiceForcingGroups) diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index 6c787048ad1..f32d8e1d1dd 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -3487,7 +3487,9 @@ subroutine column_biogeochemistry(domain) icepack_warnings_clear use seaice_constants, only: & - seaicePuny + seaicePuny, & + kilogramsToMicrograms, & + gramsIronPerMolIron type(domain_type), intent(inout) :: domain @@ -3503,6 +3505,7 @@ subroutine column_biogeochemistry(domain) melt_growth_rates, & ocean_coupling, & atmos_coupling, & + atmos_forcing, & initial ! configs @@ -3514,7 +3517,9 @@ subroutine column_biogeochemistry(domain) config_use_skeletal_biochemistry, & config_use_column_biogeochemistry, & config_use_zaerosols, & - config_use_vertical_tracers + config_use_vertical_tracers, & + config_use_atm_dust_file, & + config_use_iron_solubility_file ! dimensions integer, pointer :: & @@ -3554,7 +3559,10 @@ subroutine column_biogeochemistry(domain) oceanDMSPConc, & oceanHumicsConc, & openWaterArea, & - totalChlorophyll + totalChlorophyll, & + IRON_Zolubility_wet, & + IRON_Zolubility_dry, & + IRON_in_duzt_fraction real(kind=RKIND), dimension(:,:), pointer :: & iceAreaCategoryInitial, & @@ -3581,6 +3589,8 @@ subroutine column_biogeochemistry(domain) atmosBioFluxes, & atmosBlackCarbonFlux, & atmosDustFlux, & + atmosWetDustFlux, & + atmosDryDustFlux, & oceanBioFluxes, & oceanAlgaeConc, & oceanDOCConc, & @@ -3681,6 +3691,7 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_subpool(block % structs, "diagnostics_biogeochemistry", diagnostics_biogeochemistry) call MPAS_pool_get_subpool(block % structs, "shortwave", shortwave) call MPAS_pool_get_subpool(block % structs, "atmos_coupling", atmos_coupling) + call MPAS_pool_get_subpool(block % structs, "atmos_forcing", atmos_forcing) call MPAS_pool_get_subpool(block % structs, "melt_growth_rates", melt_growth_rates) call MPAS_pool_get_subpool(block % structs, "ocean_coupling", ocean_coupling) call MPAS_pool_get_subpool(block % structs, "initial", initial) @@ -3704,6 +3715,8 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_config(block % configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) call MPAS_pool_get_config(block % configs, "config_use_zaerosols",config_use_zaerosols) call MPAS_pool_get_config(block % configs, "config_use_vertical_tracers",config_use_vertical_tracers) + call MPAS_pool_get_config(block % configs, "config_use_atm_dust_file", config_use_atm_dust_file) + call MPAS_pool_get_config(block % configs, "config_use_iron_solubility_file", config_use_iron_solubility_file) call MPAS_pool_get_array(biogeochemistry, "newlyFormedIce", newlyFormedIce) call MPAS_pool_get_array(biogeochemistry, "netNitrateUptake", netNitrateUptake) @@ -3734,6 +3747,8 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(biogeochemistry, "atmosBioFluxes", atmosBioFluxes) call MPAS_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) call MPAS_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) + call MPAS_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxes", oceanBioFluxes) call MPAS_pool_get_array(biogeochemistry, "oceanBioFluxesCategory", oceanBioFluxesCategory) call MPAS_pool_get_array(biogeochemistry, "verticalNitrogenLosses", verticalNitrogenLosses) @@ -3763,6 +3778,10 @@ subroutine column_biogeochemistry(domain) call MPAS_pool_get_array(atmos_coupling, "snowfallRate", snowfallRate) + call MPAS_pool_get_array(atmos_forcing, "IRON_Zolubility_wet", IRON_Zolubility_wet) + call MPAS_pool_get_array(atmos_forcing, "IRON_Zolubility_dry", IRON_Zolubility_dry) + call MPAS_pool_get_array(atmos_forcing, "IRON_in_duzt_fraction", IRON_in_duzt_fraction) + call MPAS_pool_get_array(icestate, "iceAreaCategoryInitial", iceAreaCategoryInitial) call MPAS_pool_get_array(icestate, "iceVolumeCategoryInitial", iceVolumeCategoryInitial) call MPAS_pool_get_array(icestate, "snowVolumeCategoryInitial", snowVolumeCategoryInitial) @@ -3863,9 +3882,13 @@ subroutine column_biogeochemistry(domain) do iBioTracers = 1, maxBCType atmosBlackCarbonFlux(iBioTracers,iCell) = 1.e-12_RKIND enddo - do iBioTracers = 1, maxDustType - atmosDustFlux(iBioTracers,iCell) = 1.e-13_RKIND - enddo + if (.not. config_use_atm_dust_file) then + do iBioTracers = 1, maxDustType + atmosDustFlux(iBioTracers,iCell) = 1.e-13_RKIND + atmosWetDustFlux(iBioTracers,iCell) = 1.e-13_RKIND * 0.5_RKIND + atmosDryDustFlux(iBioTracers,iCell) = 1.e-13_RKIND * 0.5_RKIND + enddo + endif #endif if (config_use_zaerosols) then indexj = ciceTracerObject % index_verticalAerosolsConcLayer(1) @@ -3875,6 +3898,16 @@ subroutine column_biogeochemistry(domain) do iBioTracers = maxBCType + 1, nzAerosols atmosBioFluxes(indexj -1 + iBioTracers, iCell) = atmosDustFlux(iBioTracers-maxBCType,iCell) enddo + indexj = ciceTracerObject % index_dissolvedIronConcLayer(1) + if (config_use_iron_solubility_file) then + atmosBioFluxes(indexj,iCell) = 0.0_RKIND + do iBioTracers = maxBCType + 1, nzAerosols + atmosBioFluxes(indexj,iCell) = atmosBioFluxes(indexj,iCell) + & + (atmosWetDustFlux(iBioTracers-maxBCType,iCell) * IRON_Zolubility_wet(iCell) + & + atmosDryDustFlux(iBioTracers-maxBCType,iCell) * IRON_Zolubility_dry(iCell) ) * & + IRON_in_duzt_fraction(iCell) * kilogramsToMicrograms * gramsIronPerMolIron + end do + end if endif do iBioTracers = 1, ciceTracerObject % nBioTracers @@ -10028,7 +10061,8 @@ subroutine init_icepack_package_configs(domain) config_do_restart_bgc, & config_use_snow_liquid_ponds, & config_use_snow_grain_radius, & - config_use_shortwave_redistribution + config_use_shortwave_redistribution, & + config_use_iron_solubility_file real(kind=RKIND), pointer :: & config_min_friction_velocity, & @@ -10293,6 +10327,7 @@ subroutine init_icepack_package_configs(domain) call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) call MPAS_pool_get_config(domain % configs, "config_use_modal_aerosols", config_use_modal_aerosols) call MPAS_pool_get_config(domain % configs, "config_use_macromolecules", config_use_macromolecules) + call MPAS_pool_get_config(domain % configs, "config_use_iron_solubility_file", config_use_iron_solubility_file) call MPAS_pool_get_config(domain % configs, "config_do_restart_bgc", config_do_restart_bgc) call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) call MPAS_pool_get_config(domain % configs, "config_biogrid_bottom_molecular_sublayer", & @@ -10754,6 +10789,7 @@ subroutine init_icepack_package_configs(domain) algal_vel_in = config_algal_maximum_velocity, & R_dFe2dust_in = config_ratio_Fe_to_dust, & dustFe_sol_in = config_solubility_of_Fe_in_dust, & + use_atm_dust_iron_in = .not.config_use_iron_solubility_file, & !chlabs_diatoms_in = config_chla_absorptivity_of_diatoms, & !chlabs_sp_in = config_chla_absorptivity_of_small_plankton, & !chlabs_phaeo_in = config_chla_absorptivity_of_phaeocystis, & @@ -11369,6 +11405,10 @@ subroutine init_icepack_package_configs(domain) ! solubility fraction ! dustFe_sol = config_solubility_of_Fe_in_dust + ! use_atm_dust_sol; + ! compute dust iron contribution in icepack + ! use_atm_dust_sol = .not.config_use_iron_solubility_file + ! chlabs_diatoms: ! chl absorption (1/m/(mg/m^3)) ! chlabs_diatoms = config_chla_absorptivity_of_diatoms From bdaf63ed093c9d51819d50dbb798e0e1e309c4e1 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Fri, 24 May 2024 14:48:28 -0500 Subject: [PATCH 199/388] Update GIS 20km IG tests & add BG test Add BGWCYCL1850 test with 20km GIS; move location of existing IGELM_MLI tests and support from ./elm component dir to ./mpas-albany-landice dir; simplify tests so that they all use the same user_nl_mali and shell scripts. --- cime_config/config_files.xml | 1 + .../testmods_dirs/allactive/gis20km}/shell_commands | 0 .../testmods_dirs/allactive/gis20km}/user_nl_mali | 0 cime_config/tests.py | 5 +++-- .../elm/{gis20kmSMS => gis20km}/shell_commands | 5 ++--- .../elm/{gis20kmSMS => gis20km}/user_nl_mali | 0 .../testdefs/testmods_dirs/mali/gis20km/shell_commands | 10 ++++++++++ .../testdefs/testmods_dirs/mali/gis20km/user_nl_mali | 1 + 8 files changed, 17 insertions(+), 5 deletions(-) rename {components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS => cime_config/testmods_dirs/allactive/gis20km}/shell_commands (100%) rename {components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS => cime_config/testmods_dirs/allactive/gis20km}/user_nl_mali (100%) rename components/elm/cime_config/testdefs/testmods_dirs/elm/{gis20kmSMS => gis20km}/shell_commands (84%) rename components/elm/cime_config/testdefs/testmods_dirs/elm/{gis20kmSMS => gis20km}/user_nl_mali (100%) create mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/shell_commands create mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/user_nl_mali diff --git a/cime_config/config_files.xml b/cime_config/config_files.xml index 71de5196442..281291798db 100644 --- a/cime_config/config_files.xml +++ b/cime_config/config_files.xml @@ -351,6 +351,7 @@ $COMP_ROOT_DIR_OCN/cime_config/testdefs/testmods_dirs $COMP_ROOT_DIR_ICE/cime_config/testdefs/testmods_dirs $COMP_ROOT_DIR_WAV/cime_config/testdefs/testmods_dirs + $COMP_ROOT_DIR_GLC/cime_config/testdefs/testmods_dirs case_last env_case.xml diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/shell_commands b/cime_config/testmods_dirs/allactive/gis20km/shell_commands similarity index 100% rename from components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/shell_commands rename to cime_config/testmods_dirs/allactive/gis20km/shell_commands diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali b/cime_config/testmods_dirs/allactive/gis20km/user_nl_mali similarity index 100% rename from components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmERS/user_nl_mali rename to cime_config/testmods_dirs/allactive/gis20km/user_nl_mali diff --git a/cime_config/tests.py b/cime_config/tests.py index 0b36e7c94d0..030efe23f03 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -134,8 +134,9 @@ "e3sm_landice_developer" : { "tests" : ( - "SMS.ne30pg2_r05_EC30to60E2r2_gis20.IGELM_MLI.elm-gis20kmSMS", - "ERS.ne30pg2_r05_EC30to60E2r2_gis20.IGELM_MLI.elm-gis20kmERS", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis20.IGELM_MLI.mali-gis20km", + "ERS.ne30pg2_r05_IcoswISC30E3r5_gis20.IGELM_MLI.mali-gis20km", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis20.BGWCYCL1850.allactive-gis20km", ) }, diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20km/shell_commands similarity index 84% rename from components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/shell_commands rename to components/elm/cime_config/testdefs/testmods_dirs/elm/gis20km/shell_commands index adec2de2665..4547393d872 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/shell_commands +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20km/shell_commands @@ -1,11 +1,10 @@ ./xmlchange STOP_OPTION=ndays -./xmlchange STOP_N=2 +./xmlchange STOP_N=1 ./xmlchange REST_OPTION=ndays -./xmlchange REST_N=2 +./xmlchange REST_N=1 ./xmlchange NCPL_BASE_PERIOD=year ./xmlchange ATM_NCPL=17520 ./xmlchange LND_NCPL=17520 ./xmlchange OCN_NCPL=8760 ./xmlchange GLC_NCPL=365 ./xmlchange ROF_NCPL=17520 - diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali b/components/elm/cime_config/testdefs/testmods_dirs/elm/gis20km/user_nl_mali similarity index 100% rename from components/elm/cime_config/testdefs/testmods_dirs/elm/gis20kmSMS/user_nl_mali rename to components/elm/cime_config/testdefs/testmods_dirs/elm/gis20km/user_nl_mali diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/shell_commands b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/shell_commands new file mode 100644 index 00000000000..4547393d872 --- /dev/null +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/shell_commands @@ -0,0 +1,10 @@ +./xmlchange STOP_OPTION=ndays +./xmlchange STOP_N=1 +./xmlchange REST_OPTION=ndays +./xmlchange REST_N=1 +./xmlchange NCPL_BASE_PERIOD=year +./xmlchange ATM_NCPL=17520 +./xmlchange LND_NCPL=17520 +./xmlchange OCN_NCPL=8760 +./xmlchange GLC_NCPL=365 +./xmlchange ROF_NCPL=17520 diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/user_nl_mali b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/user_nl_mali new file mode 100644 index 00000000000..8b88e2add6c --- /dev/null +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/user_nl_mali @@ -0,0 +1 @@ +config_am_globalstats_enable = .false. From 8659988a4f6dd3abc95da8f9a0789b34cc2ca3bc Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 24 May 2024 15:56:59 -0500 Subject: [PATCH 200/388] Adds the sea ice-ocean dust flux field for coupling This field oceanDustIronFlux will be used by the ocean for dust-iron consistency across the coupled system Also corrects a bug in the calculation of iron from dust introduced in the last commit Works with E3SM-Project/Icepack.git origin/fixes-to-zaerosols-take3 BFB with zaerosols off --- components/mpas-seaice/driver/ice_comp_mct.F | 99 +++++++++++-------- .../src/shared/mpas_seaice_icepack.F | 2 +- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/components/mpas-seaice/driver/ice_comp_mct.F b/components/mpas-seaice/driver/ice_comp_mct.F index 5c1bc715518..50bf12ece37 100644 --- a/components/mpas-seaice/driver/ice_comp_mct.F +++ b/components/mpas-seaice/driver/ice_comp_mct.F @@ -2516,6 +2516,7 @@ subroutine ice_export_mct(i2x_i, errorCode) !{{{ config_rotate_cartesian_grid, & config_use_topo_meltponds, & config_use_column_biogeochemistry, & + config_use_zaerosols, & config_couple_biogeochemistry_fields, & config_use_column_shortwave, & config_use_data_icebergs @@ -2566,6 +2567,7 @@ subroutine ice_export_mct(i2x_i, errorCode) !{{{ oceanDMSPpFlux, & oceanDMSPdFlux, & oceanHumicsFlux, & + oceanDustIronFlux, & carbonToNitrogenRatioAlgae, & carbonToNitrogenRatioDON @@ -2588,6 +2590,7 @@ subroutine ice_export_mct(i2x_i, errorCode) !{{{ configs => block_ptr % configs call MPAS_pool_get_config(configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid) call MPAS_pool_get_config(configs, "config_use_topo_meltponds", config_use_topo_meltponds) + call MPAS_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_config(configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) call mpas_pool_get_config(configs, "config_couple_biogeochemistry_fields", config_couple_biogeochemistry_fields) call MPAS_pool_get_config(configs, "config_use_column_shortwave", config_use_column_shortwave) @@ -2672,6 +2675,9 @@ subroutine ice_export_mct(i2x_i, errorCode) !{{{ call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioDON', carbonToNitrogenRatioDON) endif + if (config_use_zaerosols .and. config_couple_biogeochemistry_fields) & + call mpas_pool_get_array(biogeochemistry, 'oceanDustIronFlux', oceanDustIronFlux) + do i = 1, nCellsSolve n = n + 1 @@ -2796,6 +2802,9 @@ subroutine ice_export_mct(i2x_i, errorCode) !{{{ i2x_i % rAttr(index_i2x_Fioi_fed1 ,n) = oceanDissolvedIronFlux(1,i) / 1000._RKIND i2x_i % rAttr(index_i2x_Fioi_fed2 ,n) = oceanDissolvedIronFlux(2,i) / 1000._RKIND endif + ! export dust, if configured kg/m2/s of dust + if (config_use_zaerosols .and. config_couple_biogeochemistry_fields) & + i2x_i % rAttr(index_i2x_Fioi_dust1 ,n) = oceanDustIronFlux(i) endif enddo @@ -3124,8 +3133,10 @@ subroutine ice_export_moab(EClock) config_rotate_cartesian_grid, & config_use_topo_meltponds, & config_use_column_biogeochemistry, & + config_use_zaerosols, & config_use_column_shortwave, & - config_use_data_icebergs + config_use_data_icebergs, & + config_couple_biogeochemistry_fields real(kind=RKIND), pointer :: & sphere_radius @@ -3173,6 +3184,7 @@ subroutine ice_export_moab(EClock) oceanDMSPpFlux, & oceanDMSPdFlux, & oceanHumicsFlux, & + oceanDustIronFlux, & carbonToNitrogenRatioAlgae, & carbonToNitrogenRatioDON @@ -3186,23 +3198,25 @@ subroutine ice_export_moab(EClock) integer :: ent_type, ierr, cur_ice_stepno character(len=32), parameter :: sub = 'ice_export_moab' - + character(len=100) :: outfile, wopts, localmeshfile, lnum character(CXX) :: tagname - !----------------------------------------------------------------------- + !----------------------------------------------------------------------- call shr_file_setLogUnit (iceLogUnit) n = 0 i2x_im(: ,:) = 0.0_RKIND block_ptr => domain % blocklist do while(associated(block_ptr)) - + configs => block_ptr % configs call MPAS_pool_get_config(configs, "config_rotate_cartesian_grid", config_rotate_cartesian_grid) call MPAS_pool_get_config(configs, "config_use_topo_meltponds", config_use_topo_meltponds) + call MPAS_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) call MPAS_pool_get_config(configs, "config_use_column_biogeochemistry", config_use_column_biogeochemistry) + call mpas_pool_get_config(configs, "config_couple_biogeochemistry_fields", config_couple_biogeochemistry_fields) call MPAS_pool_get_config(configs, "config_use_column_shortwave", config_use_column_shortwave) call MPAS_pool_get_config(configs, "config_use_data_icebergs", config_use_data_icebergs) - + call MPAS_pool_get_subpool(block_ptr % structs, 'mesh', meshPool) call MPAS_pool_get_subpool(block_ptr % structs, "tracers_aggregate", tracersAggregate) call MPAS_pool_get_subpool(block_ptr % structs, "velocity_solver", velocitySolver) @@ -3211,7 +3225,7 @@ subroutine ice_export_moab(EClock) call MPAS_pool_get_subpool(block_ptr % structs, 'ocean_coupling', oceanCoupling) call MPAS_pool_get_subpool(block_ptr % structs, "atmos_fluxes", atmosFluxes) call MPAS_pool_get_subpool(block_ptr % structs, "ocean_fluxes", oceanFluxes) - + call MPAS_pool_get_dimension(meshPool, 'nCellsSolve', nCellsSolve) call MPAS_pool_get_config(meshPool, "sphere_radius", sphere_radius) call MPAS_pool_get_array(meshPool, "latCell", latCell) @@ -3219,7 +3233,7 @@ subroutine ice_export_moab(EClock) call MPAS_pool_get_array(meshPool, "xCell", xCell) call MPAS_pool_get_array(meshPool, "yCell", yCell) call MPAS_pool_get_array(meshPool, "zCell", zCell) - + call MPAS_pool_get_array(tracersAggregate, 'iceAreaCell', iceAreaCell) call MPAS_pool_get_array(tracersAggregate, 'iceVolumeCell', iceVolumeCell) call MPAS_pool_get_array(tracersAggregate, 'snowVolumeCell', snowVolumeCell) @@ -3227,44 +3241,44 @@ subroutine ice_export_moab(EClock) call MPAS_pool_get_array(tracersAggregate, 'pondLidThicknessCell', pondLidThicknessCell) call MPAS_pool_get_array(tracersAggregate, 'pondAreaCell', pondAreaCell) call MPAS_pool_get_array(tracersAggregate, 'surfaceTemperatureCell', surfaceTemperatureCell) - + call MPAS_pool_get_array(velocitySolver, 'airStressCellU', airStressCellU) call MPAS_pool_get_array(velocitySolver, 'airStressCellV', airStressCellV) call MPAS_pool_get_array(velocitySolver, 'oceanStressCellU', oceanStressCellU) call MPAS_pool_get_array(velocitySolver, 'oceanStressCellV', oceanStressCellV) - + call MPAS_pool_get_array(shortwave, 'albedoVisibleDirectCell', albedoVisibleDirectCell) call MPAS_pool_get_array(shortwave, 'albedoIRDirectCell', albedoIRDirectCell) call MPAS_pool_get_array(shortwave, 'albedoVisibleDiffuseCell', albedoVisibleDiffuseCell) call MPAS_pool_get_array(shortwave, 'albedoIRDiffuseCell', albedoIRDiffuseCell) call MPAS_pool_get_array(shortwave, 'absorbedShortwaveFlux', absorbedShortwaveFlux) - + call MPAS_pool_get_array(atmosCoupling, 'atmosReferenceSpeed10m', atmosReferenceSpeed10m) call MPAS_pool_get_array(atmosCoupling, 'atmosReferenceTemperature2m', atmosReferenceTemperature2m) call MPAS_pool_get_array(atmosCoupling, 'atmosReferenceHumidity2m', atmosReferenceHumidity2m) - + call MPAS_pool_get_array(oceanCoupling, 'frazilMassAdjust', frazilMassAdjust) - + call MPAS_pool_get_array(atmosFluxes, 'latentHeatFlux', latentHeatFlux) call MPAS_pool_get_array(atmosFluxes, 'sensibleHeatFlux', sensibleHeatFlux) call MPAS_pool_get_array(atmosFluxes, 'longwaveUp', longwaveUp) call MPAS_pool_get_array(atmosFluxes, 'evaporativeWaterFlux', evaporativeWaterFlux) - + call MPAS_pool_get_array(oceanFluxes, 'oceanHeatFlux', oceanHeatFlux) call MPAS_pool_get_array(oceanFluxes, 'oceanShortwaveFlux', oceanShortwaveFlux) call MPAS_pool_get_array(oceanFluxes, 'oceanFreshWaterFlux', oceanFreshWaterFlux) call MPAS_pool_get_array(oceanFluxes, 'oceanSaltFlux', oceanSaltFlux) - + if (config_use_data_icebergs) then call MPAS_pool_get_subpool(block_ptr % structs, "berg_fluxes", icebergFluxes) - + call MPAS_pool_get_array(icebergFluxes, "bergFreshwaterFlux", bergFreshwaterFlux) call MPAS_pool_get_array(icebergFluxes, "bergLatentHeatFlux", bergLatentHeatFlux) endif - - if (config_use_column_biogeochemistry) then + + if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then call mpas_pool_get_subpool(block_ptr % structs, 'biogeochemistry', biogeochemistry) - + call mpas_pool_get_array(biogeochemistry, 'oceanAlgaeFlux', oceanAlgaeFlux) call mpas_pool_get_array(biogeochemistry, 'oceanDOCFlux', oceanDOCFlux) call mpas_pool_get_array(biogeochemistry, 'oceanDICFlux', oceanDICFlux) @@ -3281,18 +3295,20 @@ subroutine ice_export_moab(EClock) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioAlgae', carbonToNitrogenRatioAlgae) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioDON', carbonToNitrogenRatioDON) endif - + if (config_use_zaerosols .and. config_couple_biogeochemistry_fields) & + call mpas_pool_get_array(biogeochemistry, 'oceanDustIronFlux', oceanDustIronFlux) + do i = 1, nCellsSolve n = n + 1 - + ! ice fraction ailohi = min(iceAreaCell(i), 1.0_RKIND) - + !TODO: CICE has a check for ailohi < 0 - + ! surface temperature Tsrf = seaiceFreshWaterFreezingPoint + surfaceTemperatureCell(i) - + ! basal pressure if ( ailohi > 0.0_RKIND ) then call basal_pressure(& @@ -3304,7 +3320,7 @@ subroutine ice_export_moab(EClock) pondAreaCell(i), & config_use_topo_meltponds) endif - + ! wind stress (on T-grid: convert to lat-lon) call seaice_latlon_vector_rotation_backward(& tauxa, & @@ -3318,7 +3334,7 @@ subroutine ice_export_moab(EClock) zCell(i), & sphere_radius, & config_rotate_cartesian_grid) - + ! ice/ocean stress (on POP T-grid: convert to lat-lon) call seaice_latlon_vector_rotation_backward(& tauxo, & @@ -3332,25 +3348,25 @@ subroutine ice_export_moab(EClock) zCell(i), & sphere_radius, & config_rotate_cartesian_grid) - - !-------states-------------------- + + !-------states-------------------- i2x_im(n, index_i2x_Si_ifrac) = ailohi - + if (config_use_data_icebergs) then i2x_im(n, index_i2x_Fioi_bergw) = bergFreshwaterFlux(i) i2x_im(n, index_i2x_Fioi_bergh) = bergLatentHeatFlux(i) endif - + if ( ailohi > 0.0_RKIND ) then - - !-------states-------------------- + + !-------states-------------------- i2x_im(n, index_i2x_Si_t) = Tsrf i2x_im(n, index_i2x_Si_bpress) = basalPressure i2x_im(n, index_i2x_Si_u10) = atmosReferenceSpeed10m(i) i2x_im(n, index_i2x_Si_tref) = atmosReferenceTemperature2m(i) i2x_im(n, index_i2x_Si_qref) = atmosReferenceHumidity2m(i) i2x_im(n, index_i2x_Si_snowh) = snowVolumeCell(i) / ailohi - + !--- a/i fluxes computed by ice i2x_im(n, index_i2x_Faii_taux) = tauxa i2x_im(n, index_i2x_Faii_tauy) = tauya @@ -3360,17 +3376,17 @@ subroutine ice_export_moab(EClock) i2x_im(n, index_i2x_Faii_evap) = evaporativeWaterFlux(i) i2x_im(n, index_i2x_Faii_swnet) = absorbedShortwaveFlux(i) i2x_im(n, index_i2x_Faii_evap) = evaporativeWaterFlux(i) - + if (config_use_column_shortwave) then i2x_im(n, index_i2x_Si_avsdr) = albedoVisibleDirectCell(i) i2x_im(n, index_i2x_Si_anidr) = albedoIRDirectCell(i) i2x_im(n, index_i2x_Si_avsdf) = albedoVisibleDiffuseCell(i) i2x_im(n, index_i2x_Si_anidf) = albedoIRDiffuseCell(i) - + i2x_im(n, index_i2x_Faii_swnet) = absorbedShortwaveFlux(i) endif - - ! i/o fluxes computed by ice, as well as additional freshwater and salt calculated at the last + + ! i/o fluxes computed by ice, as well as additional freshwater and salt calculated at the last ! coupling import and needed to grow sea ice from frazil passed from the ocean model in the ! field frazilMassAdjust. i2x_im(n, index_i2x_Fioi_melth) = oceanHeatFlux(i) @@ -3379,9 +3395,9 @@ subroutine ice_export_moab(EClock) i2x_im(n, index_i2x_Fioi_salt ) = oceanSaltFlux(i) + seaiceReferenceSalinity*0.001_RKIND*frazilMassAdjust(i)/ailohi i2x_im(n, index_i2x_Fioi_taux ) = tauxo i2x_im(n, index_i2x_Fioi_tauy ) = tauyo - + ! export biogeochemistry fields, if configured - if (config_use_column_biogeochemistry) then + if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then ! convert from mmol N/m^3 to mmol C/m^3 i2x_im(n, index_i2x_Fioi_algae1) = oceanAlgaeFlux(1,i) * carbonToNitrogenRatioAlgae(1) i2x_im(n, index_i2x_Fioi_algae2) = oceanAlgaeFlux(2,i) * carbonToNitrogenRatioAlgae(2) @@ -3404,9 +3420,12 @@ subroutine ice_export_moab(EClock) i2x_im(n, index_i2x_Fioi_fed1 ) = oceanDissolvedIronFlux(1,i) / 1000._RKIND i2x_im(n, index_i2x_Fioi_fed2 ) = oceanDissolvedIronFlux(2,i) / 1000._RKIND endif + ! export dust, kg/m2/s + if (config_use_zaerosols .and. config_couple_biogeochemistry_fields) & + i2x_im(n, index_i2x_Fioi_dust1 ) = oceanDustIronFlux(i) endif enddo - + block_ptr => block_ptr % next enddo @@ -3417,7 +3436,7 @@ subroutine ice_export_moab(EClock) if ( ierr /= 0 ) then write(iceLogUnit,*) 'Fail to set MOAB fields ' endif - + call seq_timemgr_EClockGetData( EClock, stepno=cur_ice_stepno ) #ifdef MOABDEBUG write(lnum,"(I0.2)")cur_ice_stepno diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index f32d8e1d1dd..adee0c072b4 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -3905,7 +3905,7 @@ subroutine column_biogeochemistry(domain) atmosBioFluxes(indexj,iCell) = atmosBioFluxes(indexj,iCell) + & (atmosWetDustFlux(iBioTracers-maxBCType,iCell) * IRON_Zolubility_wet(iCell) + & atmosDryDustFlux(iBioTracers-maxBCType,iCell) * IRON_Zolubility_dry(iCell) ) * & - IRON_in_duzt_fraction(iCell) * kilogramsToMicrograms * gramsIronPerMolIron + IRON_in_duzt_fraction(iCell) * kilogramsToMicrograms / gramsIronPerMolIron end do end if endif From 9535815fa5419e726d90c0fe1c7af27ce789ec4a Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Mon, 27 May 2024 15:20:59 -0500 Subject: [PATCH 201/388] Move bgc indexing definitions to the interface -adds subroutine in the icepack interface, init_zbgc_tracer_indices, to replace icepack_init_zbgc_tracer_indices. -moves icepack_init_bgc_trcr from icepack to init_bgc_tracer_indices in mpas_seaice_icepack Tested in GCASE with ice-ocean bgc and aerosols active works with njeffery/Icepack.git branch: fixes-to-bgc-indices --- components/mpas-seaice/cime_config/buildnml | 2 +- .../src/shared/mpas_seaice_forcing.F | 7 - .../src/shared/mpas_seaice_icepack.F | 935 ++++++++++++++++-- 3 files changed, 853 insertions(+), 91 deletions(-) diff --git a/components/mpas-seaice/cime_config/buildnml b/components/mpas-seaice/cime_config/buildnml index 5aa44cf06b9..c79de6314b0 100755 --- a/components/mpas-seaice/cime_config/buildnml +++ b/components/mpas-seaice/cime_config/buildnml @@ -594,7 +594,7 @@ def buildnml(case, caseroot, compname): lines.append('') lines.append('') diff --git a/components/mpas-seaice/src/shared/mpas_seaice_forcing.F b/components/mpas-seaice/src/shared/mpas_seaice_forcing.F index 5fba5fa7d5e..ca0c4c5a962 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_forcing.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_forcing.F @@ -1841,18 +1841,11 @@ subroutine init_atm_iron_bgc_forcing(domain, clock) forcingIntervalMonthly, & forcingReferenceTimeMonthly - type (MPAS_Time_Type) :: currTime - character(len=strKIND) :: timeStamp - integer :: ierr ! get forcing configuration options call MPAS_pool_get_config(domain % configs, "config_do_restart", config_do_restart) ! create the dust iron solubility forcing group - currTime = mpas_get_clock_time(clock, MPAS_NOW, ierr) - call mpas_get_time(curr_time=currTime, dateTimeString=timeStamp, ierr=ierr) - timeStamp = '0000'//trim(timeStamp(5:)) - call MPAS_forcing_init_group(& seaiceForcingGroups, & "seaice_atm_bgc_forcing_monthly", & diff --git a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F index adee0c072b4..fd49a8c383a 100644 --- a/components/mpas-seaice/src/shared/mpas_seaice_icepack.F +++ b/components/mpas-seaice/src/shared/mpas_seaice_icepack.F @@ -12948,7 +12948,6 @@ end subroutine seaice_column_reinitialize_oceanic_fluxes subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) use icepack_intfc, only: icepack_init_zbgc - use icepack_intfc, only: icepack_init_zbgc_tracer_indices use icepack_intfc, only: icepack_init_parameters use icepack_intfc, only: icepack_query_parameters @@ -13089,6 +13088,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) nParticulateIron, & nDissolvedIron, & nzAerosols, & + nZBGCTracers, & maxAerosolType, & maxAlgaeType, & maxDOCType, & @@ -13106,6 +13106,12 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) real(kind=RKIND) :: & rtmp1, & rtmp2 + real (kind=RKIND), dimension (:), allocatable :: & + BGCTracerType, & + initialMobileFraction, & + retentionTime, & + releaseTime, & + newIceBGCFraction ! save tracer array size nTracers_temp = tracerObject % nTracers @@ -13246,6 +13252,7 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nParticulateIron", nParticulateIron) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDissolvedIron", nDissolvedIron) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nzAerosols", nzAerosols) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nZBGCTracers", nZBGCTracers) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxAerosolType", maxAerosolType) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxAlgaeType", maxAlgaeType) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxDOCType", maxDOCType) @@ -13253,6 +13260,18 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxDONType", maxDONType) call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxIronType", maxIronType) + allocate(BGCTracerType(nZBGCTracers)) + allocate(initialMobileFraction(nZBGCTracers)) + allocate(retentionTime(nZBGCTracers)) + allocate(releaseTime(nZBGCTracers)) + allocate(newIceBGCFraction(nZBGCTracers)) + + retentionTime(:) = 0.0_RKIND + releaseTime(:) = 0.0_RKIND + initialMobileFraction(:) = 0.0_RKIND + BGCTracerType(:) = 0.0_RKIND + newIceBGCFraction(:) = 0.0_RKIND + use_nitrogen = .false. if (config_use_skeletal_biochemistry .or. config_use_vertical_biochemistry) & use_nitrogen = .true. @@ -13394,84 +13413,15 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) tau_min_in=config_rapid_mobile_to_stationary_time, & tau_max_in=config_long_mobile_to_stationary_time) - call icepack_init_zbgc_tracer_indices(& - nilyr_in=nIceLayers, & - nslyr_in=nSnowLayers, & - nblyr_in=nBioLayers, & - n_algae_in=nAlgae, & - n_zaero_in=nzAerosols, & - n_doc_in=nDOC, & - n_dic_in=nDIC, & - n_don_in=nDON, & - n_fed_in=nDissolvedIron, & - n_fep_in=nParticulateIron, & - trcr_base=tracerObject % firstAncestorMask, & - trcr_depend=tracerObject % parentIndex, & - n_trcr_strata=tracerObject % ancestorNumber, & - nt_strata=tracerObject % ancestorIndices, & - nbtrcr_sw_out=tracerObject % nBioTracersShortwave, & - tr_brine_in=config_use_brine, & - nt_fbri_out=tracerObject % index_brineFraction,& - ntrcr_out=tracerObject % nTracers, & - nbtrcr_out=tracerObject % nBioTracers, & - ntrcr_o_out=tracerObject % nTracersNotBio, & - nt_bgc_Nit_out=tracerObject % index_nitrateConc, & - nt_bgc_Am_out=tracerObject % index_ammoniumConc, & - nt_bgc_Sil_out=tracerObject % index_silicateConc, & - nt_bgc_DMS_out=tracerObject % index_DMSConc, & - nt_bgc_PON_out=tracerObject % index_nonreactiveConc, & - nt_bgc_N_out=tracerObject % index_algaeConc, & - nt_bgc_C_out=tracerObject % index_algalCarbon, & - nt_bgc_chl_out=tracerObject % index_algalChlorophyll, & - nt_bgc_DOC_out=tracerObject % index_DOCConc, & - nt_bgc_DON_out=tracerObject % index_DONConc, & - nt_bgc_DIC_out=tracerObject % index_DICConc, & - nt_zaero_out=tracerObject % index_verticalAerosolsConc, & - nt_bgc_DMSPp_out=tracerObject % index_DMSPpConc, & - nt_bgc_DMSPd_out=tracerObject % index_DMSPdConc, & - nt_bgc_Fed_out=tracerObject % index_dissolvedIronConc, & - nt_bgc_Fep_out=tracerObject % index_particulateIronConc, & - nt_zbgc_frac_out=tracerObject % index_mobileFraction, & - tr_bgc_Nit_in=config_use_nitrate, & - tr_bgc_Am_in=config_use_ammonium, & - tr_bgc_Sil_in=config_use_silicate, & - tr_bgc_DMS_in=config_use_DMS, & - tr_bgc_PON_in=config_use_nonreactive, & - tr_bgc_N_in=use_nitrogen, & - tr_bgc_C_in=config_use_carbon, & - tr_bgc_chl_in=config_use_chlorophyll, & - tr_bgc_DON_in=config_use_DON, & - tr_bgc_Fe_in=config_use_iron,& - tr_zaero_in=config_use_zaerosols, & - nlt_zaero_sw_out=tracerObject % index_verticalAerosolsConcShortwave, & - nlt_chl_sw_out=tracerObject % index_chlorophyllShortwave, & - nlt_bgc_N_out=tracerObject % index_algaeConcLayer, & - nlt_bgc_Nit_out=tracerObject % index_nitrateConcLayer, & - nlt_bgc_Am_out=tracerObject % index_ammoniumConcLayer, & - nlt_bgc_Sil_out=tracerObject % index_silicateConcLayer, & - nlt_bgc_DMS_out=tracerObject % index_DMSConcLayer, & - nlt_bgc_DMSPp_out=tracerObject % index_DMSPpConcLayer, & - nlt_bgc_DMSPd_out=tracerObject % index_DMSPdConcLayer, & - nlt_bgc_C_out=tracerObject % index_algalCarbonLayer, & - nlt_bgc_chl_out=tracerObject % index_algalChlorophyllLayer, & - nlt_bgc_DIC_out=tracerObject % index_DICConcLayer, & - nlt_bgc_DOC_out=tracerObject % index_DOCConcLayer, & - nlt_bgc_PON_out=tracerObject % index_nonreactiveConcLayer, & - nlt_bgc_DON_out=tracerObject % index_DONConcLayer, & - nlt_bgc_Fed_out=tracerObject % index_dissolvedIronConcLayer, & - nlt_bgc_Fep_out=tracerObject % index_particulateIronConcLayer, & - nlt_zaero_out=tracerObject % index_verticalAerosolsConcLayer, & - nt_bgc_hum_out=tracerObject % index_humicsConc, & - nlt_bgc_hum_out=tracerObject % index_humicsConcLayer, & - tr_bgc_hum_in=config_use_humics, & - skl_bgc_in=config_use_skeletal_biochemistry, & - z_tracers_in=config_use_vertical_tracers, & - dEdd_algae_in=config_use_shortwave_bioabsorption, & - solve_zbgc_in=config_use_vertical_biochemistry, & - bio_index_o_out=tracerObject % index_LayerIndexToDataArray, & - bio_index_out=tracerObject % index_LayerIndexToBioIndex) - - call icepack_init_zbgc() + call init_zbgc_tracer_indices(domain, tracerObject, use_nitrogen, nTracers_temp, & + BGCTracerType, initialMobileFraction, retentionTime, & + releaseTime, newIceBGCFraction) + + call icepack_init_zbgc(bgc_tracer_type_in=BGCTracerType, & + zbgc_frac_init_in=initialMobileFraction, & + tau_ret_in=retentionTime, & + tau_rel_in=releaseTime, & + zbgc_init_frac_in=newIceBGCFraction) ! check calculated tracer array size if (nTracers_temp /= tracerObject % nTracers) then @@ -13494,8 +13444,827 @@ subroutine init_column_tracer_object_for_biogeochemistry(domain, tracerObject) call icepack_query_parameters(tau_max_out=rtmp2) if (rtmp1 /= rtmp2) call mpas_log_write('tau_max differs $r $r',realArgs=(/rtmp1,rtmp2/)) + deallocate(BGCTracerType) + deallocate(initialMobileFraction) + deallocate(retentionTime) + deallocate(releaseTime) + deallocate(newIceBGCFraction) + end subroutine init_column_tracer_object_for_biogeochemistry +!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +! +! init_zbgc_tracer_indices +! +!> \brief +!> \author Nicole Jeffery, LANL +!> \date 24 May 2024 +!> \details +!> Moves icepack_init_zbgc_tracer_indices to the interface +! +!----------------------------------------------------------------------- + + subroutine init_zbgc_tracer_indices(domain, tracerObject, use_nitrogen, nTracersTemp, & + BGCTracerType, initialMobileFraction, retentionTime, & + releaseTime, newIceBGCFraction) + + type(domain_type), intent(in) :: & + domain + + type(ciceTracerObjectType), intent(inout) :: & + tracerObject + + real(kind=RKIND), dimension(:), intent(inout) :: & + BGCTracerType, & + initialMobileFraction, & + retentionTime, & + releaseTime, & + newIceBGCFraction + + integer, intent(in) :: & + nTracersTemp + + logical, intent(in) :: & + use_nitrogen + + logical, pointer :: & + config_use_brine, & + config_use_vertical_zsalinity, & !echmod deprecate + config_use_vertical_biochemistry, & + config_use_vertical_tracers, & + config_use_skeletal_biochemistry, & + config_use_shortwave_bioabsorption, & + config_use_nitrate, & + config_use_carbon, & + config_use_chlorophyll, & + config_use_ammonium, & + config_use_silicate, & + config_use_DMS, & + config_use_nonreactive, & + config_use_humics, & + config_use_DON, & + config_use_iron, & + config_use_zaerosols + + real(kind=RKIND), pointer :: & + config_mobility_type_diatoms, & + config_mobility_type_small_plankton, & + config_mobility_type_phaeocystis, & + config_mobility_type_nitrate, & + config_mobility_type_ammonium, & + config_mobility_type_silicate, & + config_mobility_type_DMSPp, & + config_mobility_type_DMSPd, & + config_mobility_type_humics, & + config_mobility_type_saccharids, & + config_mobility_type_lipids, & + config_mobility_type_inorganic_carbon, & + config_mobility_type_proteins, & + config_mobility_type_dissolved_iron, & + config_mobility_type_particulate_iron, & + config_mobility_type_black_carbon1, & + config_mobility_type_black_carbon2, & + config_mobility_type_dust1, & + config_mobility_type_dust2, & + config_mobility_type_dust3, & + config_mobility_type_dust4, & + config_rapid_mobile_to_stationary_time, & + config_long_mobile_to_stationary_time, & + config_fraction_biotracer_in_frazil, & + config_new_ice_fraction_biotracer + + integer, pointer :: & + nIceLayers, & + nSnowLayers, & + nBioLayers, & + nAlgae, & + nDOC, & + nDIC, & + nDON, & + nParticulateIron, & + nDissolvedIron, & + nzAerosols, & + nZBGCTracers, & + maxAerosolType, & + maxAlgaeType, & + maxDOCType, & + maxDICType, & + maxDONType, & + maxIronType + + integer :: & + iAerosols, & + nTracerDependOption, & + nCount, & + nTracerDepend, & + iBioLayer, & + iBioTracer + + real(kind=RKIND) :: & + rtmp1, & + rtmp2 + + real (kind=RKIND), dimension (:), allocatable :: & + algalType, & + docType, & + dicType, & + donType, & + fedType, & + fepType, & + zAeroType + + call MPAS_pool_get_config(domain % configs, "config_use_brine", config_use_brine) + call MPAS_pool_get_config(domain % configs, "config_use_vertical_zsalinity", config_use_vertical_zsalinity) !echmod deprecate + call MPAS_pool_get_config(domain % configs, "config_use_shortwave_bioabsorption", config_use_shortwave_bioabsorption) + call MPAS_pool_get_config(domain % configs, "config_use_vertical_tracers", config_use_vertical_tracers) + call MPAS_pool_get_config(domain % configs, "config_use_skeletal_biochemistry", config_use_skeletal_biochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_vertical_biochemistry", config_use_vertical_biochemistry) + call MPAS_pool_get_config(domain % configs, "config_use_nitrate", config_use_nitrate) + call MPAS_pool_get_config(domain % configs, "config_use_carbon", config_use_carbon) + call MPAS_pool_get_config(domain % configs, "config_use_chlorophyll", config_use_chlorophyll) + call MPAS_pool_get_config(domain % configs, "config_use_ammonium", config_use_ammonium) + call MPAS_pool_get_config(domain % configs, "config_use_silicate", config_use_silicate) + call MPAS_pool_get_config(domain % configs, "config_use_DMS", config_use_DMS) + call MPAS_pool_get_config(domain % configs, "config_use_nonreactive", config_use_nonreactive) + call MPAS_pool_get_config(domain % configs, "config_use_humics", config_use_humics) + call MPAS_pool_get_config(domain % configs, "config_use_DON", config_use_DON) + call MPAS_pool_get_config(domain % configs, "config_use_iron", config_use_iron) + call MPAS_pool_get_config(domain % configs, "config_use_zaerosols", config_use_zaerosols) + + call MPAS_pool_get_config(domain % configs, "config_mobility_type_diatoms", config_mobility_type_diatoms) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_small_plankton", config_mobility_type_small_plankton) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_phaeocystis", config_mobility_type_phaeocystis) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_nitrate", config_mobility_type_nitrate) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_ammonium", config_mobility_type_ammonium) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_silicate", config_mobility_type_silicate) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_DMSPp", config_mobility_type_DMSPp) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_DMSPd", config_mobility_type_DMSPd) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_humics", config_mobility_type_humics) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_saccharids", config_mobility_type_saccharids) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_lipids", config_mobility_type_lipids) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_inorganic_carbon", config_mobility_type_inorganic_carbon) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_proteins", config_mobility_type_proteins) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_dissolved_iron", config_mobility_type_dissolved_iron) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_particulate_iron", config_mobility_type_particulate_iron) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_black_carbon1", config_mobility_type_black_carbon1) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_black_carbon2", config_mobility_type_black_carbon2) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust1", config_mobility_type_dust1) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust2", config_mobility_type_dust2) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust3", config_mobility_type_dust3) + call MPAS_pool_get_config(domain % configs, "config_mobility_type_dust4", config_mobility_type_dust4) + call MPAS_pool_get_config(domain % configs, "config_rapid_mobile_to_stationary_time", & + config_rapid_mobile_to_stationary_time) + call MPAS_pool_get_config(domain % configs, "config_long_mobile_to_stationary_time", & + config_long_mobile_to_stationary_time) + call MPAS_pool_get_config(domain % configs, "config_fraction_biotracer_in_frazil", & + config_fraction_biotracer_in_frazil) + call MPAS_pool_get_config(domain % configs, "config_new_ice_fraction_biotracer", & + config_new_ice_fraction_biotracer) + + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nIceLayers", nIceLayers) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nSnowLayers", nSnowLayers) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nBioLayers",nBioLayers) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nAlgae", nAlgae) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDOC", nDOC) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDIC", nDIC) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDON", nDON) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nParticulateIron", nParticulateIron) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nDissolvedIron", nDissolvedIron) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nzAerosols", nzAerosols) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "nZBGCTracers", nZBGCTracers) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxAerosolType", maxAerosolType) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxAlgaeType", maxAlgaeType) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxDOCType", maxDOCType) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxDICType", maxDICType) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxDONType", maxDONType) + call MPAS_pool_get_dimension(domain % blocklist % dimensions, "maxIronType", maxIronType) + + tracerObject % nTracersNotBio = tracerObject % nTracers + tracerObject % index_brineFraction = 0 + if (config_use_brine) then + tracerObject % index_brineFraction = tracerObject % nTracers + 1 ! ice volume fraction with salt + tracerObject % nTracers = tracerObject % nTracers + 1 + tracerObject % parentIndex(tracerObject % index_brineFraction) = 1 ! volume-weighted + tracerObject % firstAncestorMask (tracerObject % index_brineFraction,1) = 0.0_RKIND ! volume-weighted + tracerObject % firstAncestorMask (tracerObject % index_brineFraction,2) = 1.0_RKIND ! volume-weighted + tracerObject % firstAncestorMask (tracerObject % index_brineFraction,3) = 0.0_RKIND ! volume-weighted + tracerObject % ancestorNumber(tracerObject % index_brineFraction) = 0 + tracerObject % ancestorIndices (tracerObject % index_brineFraction,1) = 0 + tracerObject % ancestorIndices (tracerObject % index_brineFraction,2) = 0 + endif + + nTracerDependOption = 0 ! if tracerObject % index_brineFraction /= 0 then use fbri dependency + if (tracerObject % index_brineFraction == 0) nTracerDependOption = -1 ! otherwise make tracers depend on ice volume + + !----------------------------------------------------------------- + ! biogeochemistry + !----------------------------------------------------------------- + + tracerObject % nBioTracers = 0 + tracerObject % nBioTracersShortwave = 0 + + ! vectors of size maxAlgaeType + tracerObject % index_algaeConcLayer(:) = 0 + tracerObject % index_algalCarbonLayer(:) = 0 + tracerObject % index_algalChlorophyllLayer(:) = 0 + tracerObject % index_algaeConc(:) = 0 + tracerObject % index_algalCarbon(:) = 0 + tracerObject % index_algalChlorophyll(:) = 0 + + ! vectors of size maxDICType + tracerObject % index_DICConcLayer(:) = 0 + tracerObject % index_DICConc(:) = 0 + + ! vectors of size maxDOCType + tracerObject % index_DOCConcLayer(:) = 0 + tracerObject % index_DOCConc(:) = 0 + + ! vectors of size maxDONType + tracerObject % index_DONConcLayer(:) = 0 + tracerObject % index_DONConc(:) = 0 + + ! vectors of size maxIronType + tracerObject % index_dissolvedIronConcLayer(:) = 0 + tracerObject % index_particulateIronConcLayer(:) = 0 + tracerObject % index_dissolvedIronConc(:) = 0 + tracerObject % index_particulateIronConc(:) = 0 + + ! vectors of size maxAerosolType + tracerObject % index_verticalAerosolsConcLayer(:) = 0 + tracerObject % index_verticalAerosolsConcShortwave(:) = 0 + tracerObject % index_verticalAerosolsConc(:) = 0 + + tracerObject % index_nitrateConcLayer = 0 + tracerObject % index_ammoniumConcLayer = 0 + tracerObject % index_silicateConcLayer = 0 + tracerObject % index_DMSPpConcLayer = 0 + tracerObject % index_DMSPdConcLayer = 0 + tracerObject % index_DMSConcLayer = 0 + tracerObject % index_nonreactiveConcLayer = 0 + tracerObject % index_humicsConcLayer = 0 + tracerObject % index_chlorophyllShortwave = 0 + tracerObject % index_LayerIndexToBioIndex(:) = 0 + tracerObject % index_LayerIndexToDataArray(:) = 0 + + tracerObject % index_nitrateConc = 0 + tracerObject % index_ammoniumConc = 0 + tracerObject % index_silicateConc = 0 + tracerObject % index_DMSPpConc = 0 + tracerObject % index_DMSPdConc = 0 + tracerObject % index_DMSConc = 0 + tracerObject % index_nonreactiveConc = 0 + tracerObject % index_humicsConc = 0 + + allocate(algalType(maxAlgaeType)) + allocate(docType(maxDOCType)) + allocate(dicType(maxDICType)) + allocate(donType(maxDONType)) + allocate(fedType(maxIronType)) + allocate(fepType(maxIronType)) + allocate(zAeroType(maxAerosolType)) + + algalType(1) = config_mobility_type_diatoms + algalType(2) = config_mobility_type_small_plankton + algalType(3) = config_mobility_type_phaeocystis + + docType(1) = config_mobility_type_saccharids + docType(2) = config_mobility_type_lipids + + dicType(1) = config_mobility_type_inorganic_carbon + + donType(1) = config_mobility_type_proteins + + fedType(1) = config_mobility_type_dissolved_iron + fepType(1) = config_mobility_type_particulate_iron + + zAeroType(1) = config_mobility_type_black_carbon1 + zAeroType(2) = config_mobility_type_black_carbon2 + zAeroType(3) = config_mobility_type_dust1 + zAeroType(4) = config_mobility_type_dust2 + zAeroType(5) = config_mobility_type_dust3 + zAeroType(6) = config_mobility_type_dust4 + + if (config_use_skeletal_biochemistry) then + + nCount = 1 + nTracerDepend = 0 + + if (config_use_shortwave_bioabsorption) then + tracerObject % index_chlorophyllShortwave = 1 + tracerObject % nBioTracersShortwave = nIceLayers+nSnowLayers+2 ! only the bottom layer + ! will be nonzero + endif + elseif (config_use_vertical_tracers) then ! defined on nBioLayers+1 in ice + ! and 2 snow layers (snow surface + interior) + nCount = nBioLayers + 1 + nTracerDepend = 2 + tracerObject % index_brineFraction + nTracerDependOption + + if (use_nitrogen) then + if (config_use_shortwave_bioabsorption) then + tracerObject % index_chlorophyllShortwave = 1 + tracerObject % nBioTracersShortwave = nIceLayers+nSnowLayers+2 + endif + endif ! use_nitrogen + + endif ! config_use_skeletal_biochemistry or config_use_vertical_tracers + + if (config_use_skeletal_biochemistry .or. config_use_vertical_tracers) then + + !----------------------------------------------------------------- + ! assign tracer indices and dependencies + ! BGCTracerType: < 0 purely mobile , >= 0 stationary + !------------------------------------------------------------------ + + if (use_nitrogen) then + do iBioTracer = 1, nAlgae + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_algaeConc(iBioTracer), & + tracerObject % index_algaeConcLayer(iBioTracer),& + algalType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_algaeConcLayer(iBioTracer)) & + = iBioTracer + enddo ! iBioTracer + endif ! use_nitrogen + + if (config_use_nitrate) then + call init_bgc_tracer_indices(& + nCount, tracerObject % index_brineFraction, & + tracerObject % index_nitrateConc, & + tracerObject % index_nitrateConcLayer, & + config_mobility_type_nitrate, nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_nitrateConcLayer) & + = maxAlgaeType + 1 + endif ! config_use_nitrate + + if (config_use_carbon) then + ! + ! Algal C is not yet distinct from algal N + ! * Reqires exudation and/or changing C:N ratios + ! for implementation + ! + ! do iBioTracer = 1,nAlgae + ! call init_bgc_tracer_indices(nCount,tracerObject % index_brineFraction, & + ! tracerObject % index_algalCarbon(iBioTracer), & + ! tracerObject % index_algalCarbonLayer(iBioTracer), & + ! algalType(iBioTracer), nTracerDepend, & + ! tracerObject % nTracers, & + ! tracerObject % nBioTracers, & + ! BGCTracerType, & + ! tracerObject % parentIndex, & + ! tracerObject % firstAncestorMask, & + ! tracerObject % ancestorNumber, & + ! tracerObject % ancestorIndices, & + ! tracerObject % index_LayerIndexToBioIndex) + ! tracerObject % index_LayerIndexToDataArray(tracerObject % index_algalCarbonLayer(iBioTracer)) & + ! = maxAlgaeType + 1 + iBioTracer + ! enddo ! iBioTracer + + do iBioTracer = 1, nDOC + call init_bgc_tracer_indices(& + nCount, tracerObject % index_brineFraction, & + tracerObject % index_DOCConc(iBioTracer), & + tracerObject % index_DOCConcLayer(iBioTracer), & + docType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DOCConcLayer(iBioTracer)) & + = maxAlgaeType + 1 + iBioTracer + enddo ! iBioTracer + do iBioTracer = 1, nDIC + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_DICConc(iBioTracer), & + tracerObject % index_DICConcLayer(iBioTracer), & + dicType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DICConcLayer(iBioTracer)) & + = maxAlgaeType + maxDOCType + 1 + iBioTracer + enddo ! iBioTracer + endif ! config_use_carbon + + if (config_use_chlorophyll) then + do iBioTracer = 1, nAlgae + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_algalChlorophyll(iBioTracer), & + tracerObject % index_algalChlorophyllLayer(iBioTracer), & + algalType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_algalChlorophyllLayer(iBioTracer)) & + = maxAlgaeType + 1 + maxDOCType + maxDICType + iBioTracer + enddo ! iBioTracer + endif ! config_use_chlorophyll + + if (config_use_ammonium) then + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_ammoniumConc, & + tracerObject % index_ammoniumConcLayer, & + config_mobility_type_ammonium, & + nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_ammoniumConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 2 + endif + if (config_use_silicate) then + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_silicateConc, & + tracerObject % index_silicateConcLayer, & + config_mobility_type_silicate, & + nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_silicateConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 3 + endif + if (config_use_DMS) then ! all together + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_DMSPpConc, & + tracerObject % index_DMSPpConcLayer, & + config_mobility_type_DMSPp, nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DMSPpConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 4 + + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_DMSPdConc, & + tracerObject % index_DMSPdConcLayer, & + config_mobility_type_DMSPd, nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DMSPdConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 5 + + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_DMSConc, & + tracerObject % index_DMSConcLayer, & + config_mobility_type_DMSPd, nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DMSConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 6 + endif + if (config_use_nonreactive) then + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_nonreactiveConc, & + tracerObject % index_nonreactiveConcLayer, & + config_mobility_type_nitrate, nTracerDepend,& + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_nonreactiveConcLayer) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 7 + endif + if (config_use_DON) then + do iBioTracer = 1, nDON + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_DONConc(iBioTracer), & + tracerObject % index_DONConcLayer(iBioTracer), & + donType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_DONConcLayer(iBioTracer)) & + = 2*maxAlgaeType + maxDOCType + maxDICType + 7 + iBioTracer + enddo ! iBioTracer + endif ! config_use_DON + if (config_use_iron) then + do iBioTracer = 1, nDissolvedIron + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_dissolvedIronConc(iBioTracer), & + tracerObject % index_dissolvedIronConcLayer(iBioTracer),& + fedType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_dissolvedIronConcLayer(iBioTracer)) & + = 2*maxAlgaeType + maxDOCType + maxDICType + maxDONType + 7 + iBioTracer + enddo ! iBioTracer + do iBioTracer = 1, nParticulateIron + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_particulateIronConc(iBioTracer), & + tracerObject % index_particulateIronConcLayer(iBioTracer), & + fepType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_particulateIronConcLayer(iBioTracer)) & + = 2*maxAlgaeType + maxDOCType + maxDICType + maxDONType + maxIronType + 7 + iBioTracer + enddo ! iBioTracer + endif ! config_use_iron + + if (config_use_humics) then + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_humicsConc, & + tracerObject % index_humicsConcLayer, & + config_mobility_type_humics, nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, & + tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_humicsConcLayer) & + = 2*maxAlgaeType + maxDOCType + 8 + maxDICType + maxDONType + 2*maxIronType + maxAerosolType + endif + endif ! config_use_skeletal_biochemistry or config_use_vertical_tracers + + if (config_use_vertical_tracers) then ! defined on nBioLayers+1 in ice + ! and 2 snow layers (snow surface + interior) + nCount = nBioLayers + 1 + nTracerDepend = 2 + tracerObject % index_brineFraction + nTracerDependOption + + ! z layer aerosols + if (config_use_zaerosols) then + do iBioTracer = 1, nzAerosols + if (config_use_shortwave_bioabsorption) then + tracerObject % index_verticalAerosolsConcShortwave(iBioTracer) = & + tracerObject % nBioTracersShortwave + 1 + tracerObject % nBioTracersShortwave = & + tracerObject % nBioTracersShortwave + nIceLayers + nSnowLayers+2 + endif + call init_bgc_tracer_indices(nCount, tracerObject % index_brineFraction, & + tracerObject % index_verticalAerosolsConc(iBioTracer), & + tracerObject % index_verticalAerosolsConcLayer(iBioTracer), & + zAeroType(iBioTracer), nTracerDepend, & + tracerObject % nTracers, & + tracerObject % nBioTracers, & + BGCTracerType, tracerObject % parentIndex, & + tracerObject % firstAncestorMask, & + tracerObject % ancestorNumber, & + tracerObject % ancestorIndices, & + tracerObject % index_LayerIndexToBioIndex) + tracerObject % index_LayerIndexToDataArray(tracerObject % index_verticalAerosolsConcLayer(iBioTracer)) & + = 2*maxAlgaeType + maxDOCType + maxDICType + maxDONType + 2*maxIronType + 7 + iBioTracer + enddo ! iBioTracer + endif ! config_use_zaerosols + + tracerObject % index_mobileFraction = 0 + if (tracerObject % nBioTracers > 0) then + tracerObject % index_mobileFraction = tracerObject % nTracers + 1 + tracerObject % nTracers = tracerObject % nTracers + tracerObject % nBioTracers + do iBioLayer = 1,tracerObject % nBioTracers + initialMobileFraction(iBioLayer) = 1.0_RKIND + tracerObject % parentIndex(tracerObject % index_mobileFraction+iBioLayer-1) & + = 2+tracerObject % index_brineFraction + tracerObject % firstAncestorMask(tracerObject % index_mobileFraction+ iBioLayer - 1,1) = 0.0_RKIND + tracerObject % firstAncestorMask(tracerObject % index_mobileFraction+ iBioLayer - 1,2) = 1.0_RKIND + tracerObject % firstAncestorMask(tracerObject % index_mobileFraction+ iBioLayer - 1,3) = 0.0_RKIND + tracerObject % ancestorNumber(tracerObject % index_mobileFraction+ iBioLayer - 1) = 1 + tracerObject % ancestorIndices(tracerObject % index_mobileFraction+ iBioLayer - 1,1) & + = tracerObject % index_brineFraction + tracerObject % ancestorIndices(tracerObject % index_mobileFraction+ iBioLayer - 1,2) = 0 + retentionTime(iBioLayer) = 1.0_RKIND + releaseTime(iBioLayer) = 1.0_RKIND + + if (BGCTracerType(iBioLayer) >= 0.0_RKIND .and. BGCTracerType(iBioLayer) < 0.5_RKIND) then + retentionTime(iBioLayer) = config_rapid_mobile_to_stationary_time + releaseTime(iBioLayer) = config_long_mobile_to_stationary_time + initialMobileFraction(iBioLayer) = 1.0_RKIND + elseif (BGCTracerType(iBioLayer) >= 0.5_RKIND .and. BGCTracerType(iBioLayer) < 1.0_RKIND) then + retentionTime(iBioLayer) = config_rapid_mobile_to_stationary_time + releaseTime(iBioLayer) = config_rapid_mobile_to_stationary_time + initialMobileFraction(iBioLayer) = 1.0_RKIND + elseif (BGCTracerType(iBioLayer) >= 1.0_RKIND .and. BGCTracerType(iBioLayer) < 2.0_RKIND) then + retentionTime(iBioLayer) = config_long_mobile_to_stationary_time + releaseTime(iBioLayer) = config_rapid_mobile_to_stationary_time + initialMobileFraction(iBioLayer) = 1.0_RKIND + elseif (BGCTracerType(iBioLayer) >= 2.0_RKIND ) then + retentionTime(iBioLayer) = config_long_mobile_to_stationary_time + releaseTime(iBioLayer) = config_long_mobile_to_stationary_time + initialMobileFraction(iBioLayer) = 1.0_RKIND + endif + enddo + endif + + endif ! config_use_vertical_tracers + + do iBioLayer = 1, tracerObject % nBioTracers + newIceBGCFraction(iBioLayer) = config_fraction_biotracer_in_frazil + if (BGCTracerType(iBioLayer) < 0.0_RKIND) & + newIceBGCFraction(iBioLayer) = config_new_ice_fraction_biotracer + enddo + + if (.NOT.config_use_shortwave_bioabsorption) tracerObject % nBioTracersShortwave = 1 + + !----------------------------------------------------------------- + ! final consistency checks + !----------------------------------------------------------------- + + if (tracerObject % nBioTracers > nZBGCTracers) then + call mpas_log_write(& + "init_zbgc_tracer_indices: nBioTracers $i, greater than max nZBGCTracers: $i", & + messageType=MPAS_LOG_CRIT, intArgs=(/tracerObject % nBioTracers, nZBGCTracers/)) + endif + + deallocate(algalType) + deallocate(docType) + deallocate(dicType) + deallocate(donType) + deallocate(fedType) + deallocate(fepType) + deallocate(zAeroType) + + end subroutine init_zbgc_tracer_indices + +!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +! +! init_bgc_tracer_indices +! +!> \brief +!> \author Nicole Jeffery, LANL +!> \date 24 May 2024 +!> \details +!> +!> Moves icepack_init_bgc_trcr to the interface +! +!----------------------------------------------------------------------- + + subroutine init_bgc_tracer_indices( nCount, iBrineFraction, & + iBGCConc, iBGCConcLayer, & + BGCType, nTracerDepend, & + nTracers, nBioTracers, & + BGCTracerType, parentIndexBGC, & + firstAncestorMaskBGC, & + ancestorNumberBGC, & + ancestorIndicesBGC, & + layerIndexToBioIndex) + + integer, intent(in) :: & + nCount , & ! counter + nTracerDepend , & ! tracer dependency index + iBrineFraction + + integer, intent(inout) :: & + nTracers , & ! number of tracers + nBioTracers , & ! number of bio tracers + iBGCConc , & ! tracer index + iBGCConcLayer ! bio tracer index + + integer, dimension(:), intent(inout) :: & + parentIndexBGC , & ! tracer dependencies + ancestorNumberBGC, & ! number of underlying tracer layers + layerIndexToBioIndex + + integer, dimension(:,:), intent(inout) :: & + ancestorIndicesBGC ! indices of underlying tracer layers + + real (kind=RKIND), dimension(:,:), intent(inout) :: & + firstAncestorMaskBGC ! = 0 or 1 depending on tracer dependency + ! argument 2: (1) aice, (2) vice, (3) vsno + + real (kind=RKIND), intent(in) :: & + BGCType ! bio tracer transport type (mobile vs stationary) + + real (kind=RKIND), dimension(:), intent(inout) :: & + BGCTracerType ! bio tracer transport type array + + ! local variables + + integer :: & + iCount , & ! loop index + nTemp , & ! temporary values + ancestorIndicesBGC1, & ! temporary values + ancestorIndicesBGC2 + + real (kind=RKIND) :: & + firstAncestorMaskBGC1, & ! temporary values + firstAncestorMaskBGC2, & + firstAncestorMaskBGC3 + + iBGCConc = nTracers + 1 + nBioTracers = nBioTracers + 1 + iBGCConcLayer = nBioTracers + BGCTracerType(nBioTracers) = BGCType + + if (nCount > 1) then + ! include vertical bgc in snow + do iCount = nCount, nCount+1 + nTracers = nTracers + 1 + parentIndexBGC (iBGCConc + iCount ) = 2 ! snow volume + firstAncestorMaskBGC (iBGCConc + iCount,1) = 0.0_RKIND + firstAncestorMaskBGC (iBGCConc + iCount,2) = 0.0_RKIND + firstAncestorMaskBGC (iBGCConc + iCount,3) = 1.0_RKIND + ancestorNumberBGC(iBGCConc + iCount ) = 0 + ancestorIndicesBGC (iBGCConc + iCount,1) = 0 + ancestorIndicesBGC (iBGCConc + iCount,2) = 0 + enddo + + firstAncestorMaskBGC1 = 0.0_RKIND + firstAncestorMaskBGC2 = 1.0_RKIND + firstAncestorMaskBGC3 = 0.0_RKIND + nTemp = 1 + ancestorIndicesBGC1 = iBrineFraction + ancestorIndicesBGC2 = 0 + else ! nCount = 1 + firstAncestorMaskBGC1 = 1.0_RKIND + firstAncestorMaskBGC2 = 0.0_RKIND + firstAncestorMaskBGC3 = 0.0_RKIND + nTemp = 0 + ancestorIndicesBGC1 = 0 + ancestorIndicesBGC2 = 0 + endif ! nCount + + do iCount = 1, nCount !in ice + nTracers = nTracers + 1 + parentIndexBGC (iBGCConc + iCount - 1 ) = nTracerDepend + firstAncestorMaskBGC (iBGCConc + iCount - 1,1) = firstAncestorMaskBGC1 + firstAncestorMaskBGC (iBGCConc + iCount - 1,2) = firstAncestorMaskBGC2 + firstAncestorMaskBGC (iBGCConc + iCount - 1,3) = firstAncestorMaskBGC3 + ancestorNumberBGC(iBGCConc + iCount - 1 ) = nTemp + ancestorIndicesBGC (iBGCConc + iCount - 1,1) = ancestorIndicesBGC1 + ancestorIndicesBGC (iBGCConc + iCount - 1,2) = ancestorIndicesBGC2 + enddo + + layerIndexToBioIndex (iBGCConcLayer) = iBGCConc + + end subroutine init_bgc_tracer_indices + !||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ! ! init_column_biogeochemistry @@ -13917,10 +14686,10 @@ subroutine seaice_icepack_reinitialize_diagnostics_thermodynamics(domain) pondFreshWaterFlux(:) = 0.0_RKIND - !fresh_ai (:,:,:) = c0 - !fsalt_ai (:,:,:) = c0 - !fhocn_ai (:,:,:) = c0 - !fswthru_ai(:,:,:) = c0 + !fresh_ai (:,:,:) = 0.0_RKIND + !fsalt_ai (:,:,:) = 0.0_RKIND + !fhocn_ai (:,:,:) = 0.0_RKIND + !fswthru_ai(:,:,:) = 0.0_RKIND ! shortwave call MPAS_pool_get_subpool(block % structs, "shortwave", shortwavePool) From 1a5f91dac629fd68bc3cd42b4cc7e9de7c85bbd3 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 28 May 2024 05:50:32 -0500 Subject: [PATCH 202/388] Change high-frequency output to `append` mode This prevents the last entry from the previous run before a restart from being clobbered by a new run. --- components/mpas-ocean/cime_config/buildnml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 47076dee726..f0330621d54 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -859,7 +859,7 @@ def buildnml(case, caseroot, compname): lines.append(' filename_interval="00-01-00_00:00:00"') lines.append(' reference_time="01-01-01_00:00:00"') lines.append(' output_interval="00-00-05_00:00:00"') - lines.append(' clobber_mode="truncate"') + lines.append(' clobber_mode="append"') lines.append(' packages="highFrequencyOutputAMPKG">') lines.append('') lines.append(' ') From 7977c372dc2922286a9fee9ccb15c8c7af6b73c9 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 11 Dec 2023 21:46:11 -0800 Subject: [PATCH 203/388] Add RRSwISC6to18E3r5 to MPAS-Ocean and -Seaice --- .../namelist_defaults_mpaso.xml | 16 ++++++ components/mpas-ocean/cime_config/buildnml | 49 ++++++++++++++----- .../namelist_defaults_mpassi.xml | 4 ++ components/mpas-seaice/cime_config/buildnml | 24 +++++++-- 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml index 2880bf2ce5c..ffd45353943 100644 --- a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml +++ b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml @@ -54,6 +54,7 @@ '00:04:00' '00:02:00' '00:01:00' +'00:05:00' 'split_explicit_ab2' 2 @@ -83,6 +84,7 @@ .true. .true. .true. +.true. -1.0 .false. 30.0e3 @@ -149,6 +151,7 @@ 4.37e08 5.46e07 6.83e06 +3.2e09 1.0 .false. 0.0 @@ -165,6 +168,7 @@ .false. .false. .false. +.false. 'constant' 400.0 400.0 @@ -203,6 +207,7 @@ .false. .false. .false. +.false. 'EdenGreatbatch' 'constant' 'constant' @@ -399,6 +404,7 @@ 'pressure_only' 'pressure_only' 'pressure_only' +'pressure_only' 'Jenkins' .false. 10.0 @@ -417,6 +423,7 @@ 4.48e-3 4.48e-3 4.48e-3 +4.48e-3 1e-4 5e-2 0.011 @@ -430,6 +437,7 @@ 0.00295 0.00295 0.00295 +0.00295 3.1e-4 8.42e-5 8.42e-5 @@ -441,6 +449,7 @@ 8.42e-5 8.42e-5 8.42e-5 +8.42e-5 'flux-form' @@ -469,6 +478,7 @@ 4.48e-3 4.48e-3 4.48e-3 +4.48e-3 1.0e-3 10.0 2.5e-3 @@ -555,6 +565,7 @@ '0000_00:00:05' '0000_00:00:02.5' '0000_00:00:01.25' +'0000_00:00:10' 2 .true. 2 @@ -601,6 +612,7 @@ .false. .false. .false. +.false. .false. .false. .false. @@ -1126,6 +1138,7 @@ .true. .true. .true. +.true. '0000-00-00_01:00:00' 'mocStreamfunctionOutput' .true. @@ -1213,6 +1226,7 @@ .true. .true. .true. +.true. 'dt' 'conservationCheckOutput' .false. @@ -1224,6 +1238,7 @@ .true. .true. .true. +.true. .false. .true. .true. @@ -1233,6 +1248,7 @@ .true. .true. .true. +.true. .true. 'conservationCheckRestart' diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 47076dee726..06868179668 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -365,6 +365,20 @@ def buildnml(case, caseroot, compname): ic_date = '20240314' ic_prefix = 'mpaso.IcosXISC30E3r7.rstFromPiControlSpinup-chrysalis' + elif ocn_grid == 'RRSwISC6to18E3r5': + decomp_date = '20240327' + decomp_prefix = 'partitions/mpas-o.graph.info.' + restoring_file = 'sss.PHC2_monthlyClimatology.RRSwISC6to18E3r5.20240327.nc' + analysis_mask_file = 'RRSwISC6to18E3r5_mocBasinsAndTransects20210623.nc' + ic_date = '20240327' + ic_prefix = 'mpaso.RRSwISC6to18E3r5' + if ocn_ic_mode == 'spunup': + logger.warning("WARNING: The specified compset is requesting ocean ICs spunup from a G-case") + logger.warning(" But no file available for this grid.") + if ocn_ismf == 'data': + data_ismf_file = 'prescribed_ismf_paolo2023.RRSwISC6to18E3r5.20240327.nc' + + #-------------------------------------------------------------------- # Set OCN_FORCING = datm_forced_restoring if restoring file is available #-------------------------------------------------------------------- @@ -491,7 +505,8 @@ def buildnml(case, caseroot, compname): lines.append('') lines.append('') lines.append('') lines.append('') lines.append(' ') lines.append(' ') - if not ocn_grid.startswith("oRRS1"): + if not (ocn_grid.startswith("oRRS1") or ocn_grid.startswith("RRSwISC6")): lines.append(' ') lines.append(' ') lines.append(' ') @@ -1438,7 +1458,8 @@ def buildnml(case, caseroot, compname): lines.append('240.0 120.0 60.0 +900.0 'noleap' '2000-01-01_00:00:00' 'none' @@ -89,6 +90,7 @@ 75.0 85.0 85.0 +85.0 -60.0 -75.0 -75.0 @@ -103,6 +105,7 @@ -85.0 -85.0 -85.0 +-85.0 'uniform' 0.0 0.0 @@ -166,6 +169,7 @@ 1 1 1 +2 true true 120 diff --git a/components/mpas-seaice/cime_config/buildnml b/components/mpas-seaice/cime_config/buildnml index 8337fcfc706..b8bdf632a1e 100755 --- a/components/mpas-seaice/cime_config/buildnml +++ b/components/mpas-seaice/cime_config/buildnml @@ -318,6 +318,16 @@ def buildnml(case, caseroot, compname): grid_date = '20240314' grid_prefix = 'mpassi.IcosXISC30E3r7.rstFromPiControlSpinup-chrysalis' + elif ice_grid == 'RRSwISC6to18E3r5': + decomp_date = '20240327' + decomp_prefix = 'partitions/mpas-seaice.graph.info.' + grid_date = '20240327' + grid_prefix = 'mpassi.RRSwISC6to18E3r5' + data_iceberg_file = 'Iceberg_Climatology_Merino.RRSwISC6to18E3r5.20240327.nc' + if ice_ic_mode == 'spunup': + logger.warning("WARNING: The specified compset is requesting seaice ICs spunup from a G-case") + logger.warning(" But no file available for this grid.") + elif ice_grid == 'ICOS10': grid_date = '211015' grid_prefix = 'seaice.ICOS10' @@ -451,7 +461,8 @@ def buildnml(case, caseroot, compname): lines.append('') lines.append(' Date: Mon, 11 Dec 2023 21:55:58 -0800 Subject: [PATCH 204/388] Add RRSwISC6to18E3r5 to ELM --- components/elm/bld/namelist_files/namelist_definition.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index 0f8b03dfec3..55206b5de6b 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -1423,7 +1423,7 @@ Representative concentration pathway for future scenarios [radiative forcing at + valid_values="USGS,gx3v7,gx1v6,navy,test,tx0.1v2,tx1v1,T62,TL319,cruncep,oEC60to30v3,oEC60to30v3wLI,ECwISC30to60E1r2,EC30to60E2r2,WC14to60E2r3,WCAtl12to45E2r4,SOwISC12to60E2r4,ECwISC30to60E2r1,oRRS18to6,oRRS18to6v3,oRRS15to5,oARRM60to10,oARRM60to6,ARRM10to60E2r1,oQU480,oQU240,oQU240wLI,oQU120,oRRS30to10v3,oRRS30to10v3wLI,360x720cru,NLDASww3a,NLDAS,tx0.1v2,ICOS10,IcoswISC30E3r5,IcosXISC30E3r7,RRSwISC6to18E3r5"> Land mask description From d7d700de080d63ce590b5f2c36fe8f9e1459dddc Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 5 Apr 2024 13:57:28 -0500 Subject: [PATCH 205/388] Update the partition files for ocean and ice The new ones use a 64-bit build of gpmetis that does not leave partitions with zero cells. --- components/mpas-ocean/cime_config/buildnml | 2 +- components/mpas-seaice/cime_config/buildnml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 06868179668..99c028a8808 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -366,7 +366,7 @@ def buildnml(case, caseroot, compname): ic_prefix = 'mpaso.IcosXISC30E3r7.rstFromPiControlSpinup-chrysalis' elif ocn_grid == 'RRSwISC6to18E3r5': - decomp_date = '20240327' + decomp_date = '20240404' decomp_prefix = 'partitions/mpas-o.graph.info.' restoring_file = 'sss.PHC2_monthlyClimatology.RRSwISC6to18E3r5.20240327.nc' analysis_mask_file = 'RRSwISC6to18E3r5_mocBasinsAndTransects20210623.nc' diff --git a/components/mpas-seaice/cime_config/buildnml b/components/mpas-seaice/cime_config/buildnml index b8bdf632a1e..5522d8ac651 100755 --- a/components/mpas-seaice/cime_config/buildnml +++ b/components/mpas-seaice/cime_config/buildnml @@ -319,7 +319,7 @@ def buildnml(case, caseroot, compname): grid_prefix = 'mpassi.IcosXISC30E3r7.rstFromPiControlSpinup-chrysalis' elif ice_grid == 'RRSwISC6to18E3r5': - decomp_date = '20240327' + decomp_date = '20240404' decomp_prefix = 'partitions/mpas-seaice.graph.info.' grid_date = '20240327' grid_prefix = 'mpassi.RRSwISC6to18E3r5' From e3cdc9f5176f6be3a22a7427a745924cbb5f549d Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 28 May 2024 17:00:36 -0700 Subject: [PATCH 206/388] add namelist build check to disallow fates sp mode with fates hydro --- components/elm/bld/ELMBuildNamelist.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/elm/bld/ELMBuildNamelist.pm b/components/elm/bld/ELMBuildNamelist.pm index 250d8666d25..1500cbecd29 100755 --- a/components/elm/bld/ELMBuildNamelist.pm +++ b/components/elm/bld/ELMBuildNamelist.pm @@ -3317,6 +3317,10 @@ sub setup_logic_fates { if ( $nl->get_value('fates_spitfire_mode') > 0 ) { fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true'); } + # hydro isn't currently supported to work when FATES SP mode is active + if (&value_is_true( $nl->get_value('use_fates_planthydro') )) { + fatal_error('fates sp mode is currently not supported to work with fates hydro'); + } } } # check that fates landuse change mode has the necessary luh2 landuse timeseries data From 60fe431e22c43778991f5f66e419526a30e70924 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 28 May 2024 17:14:01 -0700 Subject: [PATCH 207/388] update default fates parameter file --- components/elm/bld/namelist_files/namelist_defaults.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index 23d05a8f772..429469df314 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -134,7 +134,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -lnd/clm2/paramdata/fates_params_api.32.0.0_12pft_c231215.nc +lnd/clm2/paramdata/fates_params_api.35.0.0_12pft_c240326.nc lnd/clm2/paramdata/CNP_parameters_c131108.nc From c54c6db758cf9e6cae0e25974c91f4c9335035c5 Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 21 May 2024 07:57:54 -0600 Subject: [PATCH 208/388] Default waterThickness/Min. effectConducEdge limit Establishes a default waterThickness to be imposed as an initial condition if no waterThickness variable exists. Forces effectiveConducEdge to zero if below 1e-30 to avoid too small of diffusivity/waterVelocity values. --- .../mpas-albany-landice/src/Registry_subglacial_hydro.xml | 2 +- .../src/mode_forward/mpas_li_subglacial_hydro.F | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml index fdc4cd0b387..8b3f07d4750 100644 --- a/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml +++ b/components/mpas-albany-landice/src/Registry_subglacial_hydro.xml @@ -152,7 +152,7 @@ - diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 344459dae95..26c33ea2849 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -845,6 +845,7 @@ subroutine calc_edge_quantities(block, err) integer :: i, j, iVertex, iCell real (kind=RKIND) :: velSign integer :: numGroundedCells + real(kind=RKIND), parameter :: SMALL_CONDUC = 1.0e-30_RKIND integer :: err_tmp err = 0 @@ -1079,6 +1080,10 @@ subroutine calc_edge_quantities(block, err) enddo endif + where (effectiveConducEdge < SMALL_CONDUC) + effectiveConducEdge = 0.0_RKIND + end where + ! calculate diffusivity on edges diffusivity(:) = rho_water * gravity * effectiveConducEdge(:) * waterThicknessEdge(:) From 8628e1a38c70fd5819b696c235e0bcc22fbc132a Mon Sep 17 00:00:00 2001 From: Alexander Hager Date: Tue, 28 May 2024 07:40:46 -0600 Subject: [PATCH 209/388] Fix typo in PR #106 Fixes typo in PR #106 that accidentally got merged. --- .../src/mode_forward/mpas_li_subglacial_hydro.F | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F index 26c33ea2849..b722459761e 100644 --- a/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F +++ b/components/mpas-albany-landice/src/mode_forward/mpas_li_subglacial_hydro.F @@ -2225,7 +2225,7 @@ subroutine ocean_connection_N(domain) call mpas_pool_get_subpool(block % structs, 'hydro', hydroPool) call mpas_pool_get_array(geometryPool, 'bedTopography', bedTopography) call mpas_pool_get_array(hydroPool, 'effectivePressure', effectivePressure) - call mpas_pool_get_array(hydroPool, 'iceThicknessHydro', thickness) + call mpas_pool_get_array(hydroPool, 'thickness', thickness) effectivePressure = rhoi * gravity * thickness - rhoi * gravity * max(0.0_RKIND, -1.0_RKIND * rhoo/rhoi * bedTopography) effectivePressure = max(effectivePressure, 0.0_RKIND) ! This is just to zero out N in the open ocean to avoid confusion From bd00c6724ce6149069407ebb6afd41faf2fd6b76 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 14:14:53 -0700 Subject: [PATCH 210/388] update fates allvars testmod with renamed history outputs --- .../elm/fates_cold_allvars/user_nl_elm | 124 ++++++++---------- 1 file changed, 54 insertions(+), 70 deletions(-) diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm index 2aff9c0b3c2..8ccaf9f5bb3 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm @@ -2,73 +2,57 @@ hist_mfilt = 365 hist_nhtfrq = -24 hist_empty_htapes = .false. fates_spitfire_mode = 1 -hist_fincl1 = 'FATES_CROWNAREA_PF', 'FATES_CANOPYCROWNAREA_PF', -'FATES_NCL_AP', 'FATES_NPATCH_AP', 'FATES_VEGC_AP', -'FATES_SECONDARY_FOREST_FRACTION', 'FATES_WOOD_PRODUCT', -'FATES_SECONDARY_FOREST_VEGC', 'FATES_SECONDAREA_ANTHRODIST_AP', -'FATES_SECONDAREA_DIST_AP', 'FATES_STOMATAL_COND_AP', 'FATES_LBLAYER_COND_AP', -'FATES_NPP_AP', 'FATES_GPP_AP', 'FATES_PARSUN_Z_CLLL', 'FATES_PARSHA_Z_CLLL', -'FATES_PARSUN_Z_CLLLPF', 'FATES_PARSHA_Z_CLLLPF', 'FATES_PARSUN_Z_CL', -'FATES_PARSHA_Z_CL', 'FATES_LAISUN_Z_CLLL', 'FATES_LAISHA_Z_CLLL', -'FATES_LAISUN_Z_CLLLPF', 'FATES_LAISHA_Z_CLLLPF', 'FATES_LAISUN_TOP_CL', -'FATES_LAISHA_TOP_CL', 'FATES_FABD_SUN_CLLLPF', 'FATES_FABD_SHA_CLLLPF', -'FATES_FABI_SUN_CLLLPF', 'FATES_FABI_SHA_CLLLPF', 'FATES_FABD_SUN_CLLL', -'FATES_FABD_SHA_CLLL', 'FATES_FABI_SUN_CLLL', 'FATES_FABI_SHA_CLLL', -'FATES_PARPROF_DIR_CLLLPF', 'FATES_PARPROF_DIF_CLLLPF','FATES_FABD_SUN_TOPLF_CL', -'FATES_FABD_SHA_TOPLF_CL', 'FATES_FABI_SUN_TOPLF_CL', 'FATES_FABI_SHA_TOPLF_CL', -'FATES_NET_C_UPTAKE_CLLL', 'FATES_CROWNAREA_CLLL', 'FATES_NPLANT_CANOPY_SZAP', -'FATES_NPLANT_USTORY_SZAP', 'FATES_DDBH_CANOPY_SZAP', 'FATES_DDBH_USTORY_SZAP', -'FATES_MORTALITY_CANOPY_SZAP', 'FATES_MORTALITY_USTORY_SZAP', -'FATES_NPLANT_SZAPPF', 'FATES_NPP_APPF', 'FATES_VEGC_APPF', 'FATES_GPP_SZPF', -'FATES_GPP_CANOPY_SZPF', 'FATES_AUTORESP_CANOPY_SZPF', 'FATES_GPP_USTORY_SZPF', -'FATES_AUTORESP_USTORY_SZPF', 'FATES_NPP_SZPF', 'FATES_LEAF_ALLOC_SZPF', -'FATES_SEED_ALLOC_SZPF', 'FATES_FROOT_ALLOC_SZPF', 'FATES_BGSAPWOOD_ALLOC_SZPF', -'FATES_BGSTRUCT_ALLOC_SZPF', 'FATES_AGSAPWOOD_ALLOC_SZPF', -'FATES_AGSTRUCT_ALLOC_SZPF', 'FATES_STORE_ALLOC_SZPF', 'FATES_DDBH_SZPF', -'FATES_GROWTHFLUX_SZPF', 'FATES_GROWTHFLUX_FUSION_SZPF', -'FATES_DDBH_CANOPY_SZPF', 'FATES_DDBH_USTORY_SZPF', 'FATES_BASALAREA_SZPF', -'FATES_VEGC_ABOVEGROUND_SZPF', 'FATES_NPLANT_SZPF', 'FATES_NPLANT_ACPF', -'FATES_MORTALITY_BACKGROUND_SZPF', 'FATES_MORTALITY_HYDRAULIC_SZPF', -'FATES_MORTALITY_CSTARV_SZPF', 'FATES_MORTALITY_IMPACT_SZPF', -'FATES_MORTALITY_FIRE_SZPF', 'FATES_MORTALITY_CROWNSCORCH_SZPF', -'FATES_MORTALITY_CAMBIALBURN_SZPF', 'FATES_MORTALITY_TERMINATION_SZPF', -'FATES_MORTALITY_LOGGING_SZPF', 'FATES_MORTALITY_FREEZING_SZPF', -'FATES_MORTALITY_SENESCENCE_SZPF', 'FATES_MORTALITY_AGESCEN_SZPF', -'FATES_MORTALITY_AGESCEN_ACPF', 'FATES_MORTALITY_CANOPY_SZPF', -'FATES_STOREC_CANOPY_SZPF', 'FATES_LEAFC_CANOPY_SZPF', -'FATES_NPLANT_CANOPY_SZPF', 'FATES_MORTALITY_USTORY_SZPF', -'FATES_STOREC_USTORY_SZPF', 'FATES_LEAFC_USTORY_SZPF', -'FATES_NPLANT_USTORY_SZPF', 'FATES_CWD_ABOVEGROUND_DC', -'FATES_CWD_BELOWGROUND_DC', 'FATES_CWD_ABOVEGROUND_IN_DC', -'FATES_CWD_BELOWGROUND_IN_DC', 'FATES_CWD_ABOVEGROUND_OUT_DC', -'FATES_CWD_BELOWGROUND_OUT_DC', 'FATES_AUTORESP_SZPF', 'FATES_GROWAR_SZPF', -'FATES_MAINTAR_SZPF', 'FATES_RDARK_SZPF', 'FATES_AGSAPMAINTAR_SZPF', -'FATES_BGSAPMAINTAR_SZPF', 'FATES_FROOTMAINTAR_SZPF', -'FATES_YESTCANLEV_CANOPY_SZ', 'FATES_YESTCANLEV_USTORY_SZ', -'FATES_VEGC_SZ', 'FATES_DEMOTION_RATE_SZ', 'FATES_PROMOTION_RATE_SZ', -'FATES_SAI_CANOPY_SZ', 'FATES_SAI_USTORY_SZ', 'FATES_NPP_CANOPY_SZ', -'FATES_NPP_USTORY_SZ', 'FATES_TRIMMING_CANOPY_SZ', 'FATES_TRIMMING_USTORY_SZ', -'FATES_CROWNAREA_CANOPY_SZ', 'FATES_CROWNAREA_USTORY_SZ', -'FATES_LEAFCTURN_CANOPY_SZ', 'FATES_FROOTCTURN_CANOPY_SZ', -'FATES_STORECTURN_CANOPY_SZ', 'FATES_STRUCTCTURN_CANOPY_SZ', -'FATES_SAPWOODCTURN_CANOPY_SZ', 'FATES_SEED_PROD_CANOPY_SZ', -'FATES_LEAF_ALLOC_CANOPY_SZ', 'FATES_FROOT_ALLOC_CANOPY_SZ', -'FATES_SAPWOOD_ALLOC_CANOPY_SZ', 'FATES_STRUCT_ALLOC_CANOPY_SZ', -'FATES_SEED_ALLOC_CANOPY_SZ', 'FATES_STORE_ALLOC_CANOPY_SZ', -'FATES_RDARK_CANOPY_SZ', 'FATES_LSTEMMAINTAR_CANOPY_SZ', -'FATES_CROOTMAINTAR_CANOPY_SZ', 'FATES_FROOTMAINTAR_CANOPY_SZ', -'FATES_GROWAR_CANOPY_SZ', 'FATES_MAINTAR_CANOPY_SZ', -'FATES_LEAFCTURN_USTORY_SZ', 'FATES_FROOTCTURN_USTORY_SZ', -'FATES_STORECTURN_USTORY_SZ', 'FATES_STRUCTCTURN_USTORY_SZ', -'FATES_SAPWOODCTURN_USTORY_SZ', 'FATES_SEED_PROD_USTORY_SZ', -'FATES_LEAF_ALLOC_USTORY_SZ', 'FATES_FROOT_ALLOC_USTORY_SZ', -'FATES_SAPWOOD_ALLOC_USTORY_SZ', 'FATES_STRUCT_ALLOC_USTORY_SZ', -'FATES_SEED_ALLOC_USTORY_SZ', 'FATES_STORE_ALLOC_USTORY_SZ', -'FATES_RDARK_USTORY_SZ', 'FATES_LSTEMMAINTAR_USTORY_SZ', -'FATES_CROOTMAINTAR_USTORY_SZ', 'FATES_FROOTMAINTAR_USTORY_SZ', -'FATES_GROWAR_USTORY_SZ', 'FATES_MAINTAR_USTORY_SZ', 'FATES_VEGC_SZPF', -'FATES_LEAFC_SZPF', 'FATES_FROOTC_SZPF', 'FATES_SAPWOODC_SZPF', -'FATES_STOREC_SZPF', 'FATES_REPROC_SZPF', 'FATES_DROUGHT_STATUS_PF', -'FATES_DAYSINCE_DROUGHTLEAFOFF_PF', 'FATES_DAYSINCE_DROUGHTLEAFON_PF', -'FATES_MEANLIQVOL_DROUGHTPHEN_PF', 'FATES_MEANSMP_DROUGHTPHEN_PF', -'FATES_ELONG_FACTOR_PF' +fates_history_dimlevel = 2,2 +use_fates_tree_damage = .true. +hist_ndens = 1 +hist_fincl1 = 'FATES_TLONGTERM', +'FATES_TGROWTH','FATES_SEEDS_IN_GRIDCELL_PF','FATES_SEEDS_OUT_GRIDCELL_PF','FATES_NCL_AP', +'FATES_NPATCH_AP','FATES_VEGC_AP','FATES_SECONDAREA_ANTHRODIST_AP','FATES_SECONDAREA_DIST_AP', +'FATES_FUEL_AMOUNT_APFC','FATES_STOREC_TF_USTORY_SZPF','FATES_STOREC_TF_CANOPY_SZPF', +'FATES_CROWNAREA_CLLL','FATES_ABOVEGROUND_MORT_SZPF', +'FATES_ABOVEGROUND_PROD_SZPF','FATES_NPLANT_SZAP','FATES_NPLANT_CANOPY_SZAP', +'FATES_NPLANT_USTORY_SZAP','FATES_DDBH_CANOPY_SZAP','FATES_DDBH_USTORY_SZAP', +'FATES_MORTALITY_CANOPY_SZAP','FATES_MORTALITY_USTORY_SZAP','FATES_NPLANT_SZAPPF', +'FATES_NPP_APPF','FATES_VEGC_APPF','FATES_SCORCH_HEIGHT_APPF','FATES_GPP_SZPF', +'FATES_GPP_CANOPY_SZPF','FATES_AUTORESP_CANOPY_SZPF','FATES_GPP_USTORY_SZPF', +'FATES_AUTORESP_USTORY_SZPF','FATES_NPP_SZPF','FATES_LEAF_ALLOC_SZPF', +'FATES_SEED_ALLOC_SZPF','FATES_FROOT_ALLOC_SZPF','FATES_BGSAPWOOD_ALLOC_SZPF', +'FATES_BGSTRUCT_ALLOC_SZPF','FATES_AGSAPWOOD_ALLOC_SZPF','FATES_AGSTRUCT_ALLOC_SZPF', +'FATES_STORE_ALLOC_SZPF','FATES_DDBH_SZPF','FATES_GROWTHFLUX_SZPF','FATES_GROWTHFLUX_FUSION_SZPF', +'FATES_DDBH_CANOPY_SZPF','FATES_DDBH_USTORY_SZPF','FATES_BASALAREA_SZPF','FATES_VEGC_ABOVEGROUND_SZPF', +'FATES_NPLANT_SZPF','FATES_NPLANT_ACPF','FATES_MORTALITY_BACKGROUND_SZPF','FATES_MORTALITY_HYDRAULIC_SZPF', +'FATES_MORTALITY_CSTARV_SZPF','FATES_MORTALITY_IMPACT_SZPF','FATES_MORTALITY_FIRE_SZPF', +'FATES_MORTALITY_CROWNSCORCH_SZPF','FATES_MORTALITY_CAMBIALBURN_SZPF','FATES_MORTALITY_TERMINATION_SZPF', +'FATES_MORTALITY_LOGGING_SZPF','FATES_MORTALITY_FREEZING_SZPF','FATES_MORTALITY_SENESCENCE_SZPF', +'FATES_MORTALITY_AGESCEN_SZPF','FATES_MORTALITY_AGESCEN_ACPF','FATES_MORTALITY_CANOPY_SZPF', +'FATES_M3_MORTALITY_CANOPY_SZPF','FATES_M3_MORTALITY_USTORY_SZPF','FATES_C13DISC_SZPF', +'FATES_STOREC_CANOPY_SZPF','FATES_LEAFC_CANOPY_SZPF','FATES_LAI_CANOPY_SZPF','FATES_CROWNAREA_CANOPY_SZPF', +'FATES_CROWNAREA_USTORY_SZPF','FATES_NPLANT_CANOPY_SZPF','FATES_MORTALITY_USTORY_SZPF','FATES_STOREC_USTORY_SZPF', +'FATES_LEAFC_USTORY_SZPF','FATES_LAI_USTORY_SZPF','FATES_NPLANT_USTORY_SZPF','FATES_CWD_ABOVEGROUND_DC', +'FATES_CWD_BELOWGROUND_DC','FATES_CWD_ABOVEGROUND_IN_DC','FATES_CWD_BELOWGROUND_IN_DC', +'FATES_CWD_ABOVEGROUND_OUT_DC','FATES_CWD_BELOWGROUND_OUT_DC','FATES_YESTCANLEV_CANOPY_SZ', +'FATES_YESTCANLEV_USTORY_SZ','FATES_VEGC_SZ','FATES_DEMOTION_RATE_SZ','FATES_PROMOTION_RATE_SZ', +'FATES_SAI_CANOPY_SZ','FATES_M3_MORTALITY_CANOPY_SZ','FATES_M3_MORTALITY_USTORY_SZ','FATES_SAI_USTORY_SZ', +'FATES_NPP_CANOPY_SZ','FATES_NPP_USTORY_SZ','FATES_TRIMMING_CANOPY_SZ','FATES_TRIMMING_USTORY_SZ', +'FATES_CROWNAREA_CANOPY_SZ','FATES_CROWNAREA_USTORY_SZ','FATES_LEAFCTURN_CANOPY_SZ','FATES_FROOTCTURN_CANOPY_SZ', +'FATES_STORECTURN_CANOPY_SZ','FATES_STRUCTCTURN_CANOPY_SZ','FATES_SAPWOODCTURN_CANOPY_SZ','FATES_SEED_PROD_CANOPY_SZ', +'FATES_LEAF_ALLOC_CANOPY_SZ','FATES_FROOT_ALLOC_CANOPY_SZ','FATES_SAPWOOD_ALLOC_CANOPY_SZ','FATES_STRUCT_ALLOC_CANOPY_SZ', +'FATES_SEED_ALLOC_CANOPY_SZ','FATES_STORE_ALLOC_CANOPY_SZ','FATES_LEAFCTURN_USTORY_SZ','FATES_FROOTCTURN_USTORY_SZ', +'FATES_STORECTURN_USTORY_SZ','FATES_STRUCTCTURN_USTORY_SZ','FATES_SAPWOODCTURN_USTORY_SZ', +'FATES_SEED_PROD_USTORY_SZ','FATES_LEAF_ALLOC_USTORY_SZ','FATES_FROOT_ALLOC_USTORY_SZ','FATES_SAPWOOD_ALLOC_USTORY_SZ', +'FATES_STRUCT_ALLOC_USTORY_SZ','FATES_SEED_ALLOC_USTORY_SZ','FATES_STORE_ALLOC_USTORY_SZ','FATES_CROWNAREA_CANOPY_CD', +'FATES_CROWNAREA_USTORY_CD','FATES_NPLANT_CDPF','FATES_NPLANT_CANOPY_CDPF','FATES_NPLANT_USTORY_CDPF', +'FATES_M3_CDPF','FATES_M11_SZPF','FATES_M11_CDPF','FATES_MORTALITY_CDPF','FATES_M3_MORTALITY_CANOPY_CDPF', +'FATES_M3_MORTALITY_USTORY_CDPF','FATES_M11_MORTALITY_CANOPY_CDPF','FATES_M11_MORTALITY_USTORY_CDPF', +'FATES_MORTALITY_CANOPY_CDPF','FATES_MORTALITY_USTORY_CDPF','FATES_DDBH_CDPF','FATES_DDBH_CANOPY_CDPF', +'FATES_DDBH_USTORY_CDPF','FATES_VEGC_SZPF','FATES_LEAFC_SZPF','FATES_FROOTC_SZPF','FATES_SAPWOODC_SZPF', +'FATES_STOREC_SZPF','FATES_REPROC_SZPF','FATES_NPP_AP','FATES_GPP_AP','FATES_RDARK_USTORY_SZ', +'FATES_LSTEMMAINTAR_USTORY_SZ','FATES_CROOTMAINTAR_USTORY_SZ','FATES_FROOTMAINTAR_USTORY_SZ','FATES_GROWAR_USTORY_SZ', +'FATES_MAINTAR_USTORY_SZ','FATES_RDARK_CANOPY_SZ','FATES_CROOTMAINTAR_CANOPY_SZ','FATES_FROOTMAINTAR_CANOPY_SZ', +'FATES_GROWAR_CANOPY_SZ','FATES_MAINTAR_CANOPY_SZ','FATES_LSTEMMAINTAR_CANOPY_SZ','FATES_AUTORESP_SZPF', +'FATES_GROWAR_SZPF','FATES_MAINTAR_SZPF','FATES_RDARK_SZPF','FATES_AGSAPMAINTAR_SZPF','FATES_BGSAPMAINTAR_SZPF', +'FATES_FROOTMAINTAR_SZPF','FATES_PARSUN_CLLL','FATES_PARSHA_CLLL','FATES_PARSUN_CLLLPF','FATES_PARSHA_CLLLPF', +'FATES_PARSUN_CL','FATES_PARSHA_CL','FATES_LAISUN_CLLL','FATES_LAISHA_CLLL','FATES_LAISUN_CLLLPF', +'FATES_LAISHA_CLLLPF','FATES_PARPROF_DIR_CLLLPF','FATES_PARPROF_DIF_CLLLPF','FATES_LAISUN_CL','FATES_LAISHA_CL', +'FATES_PARPROF_DIR_CLLL','FATES_PARPROF_DIF_CLLL','FATES_NET_C_UPTAKE_CLLL','FATES_CROWNFRAC_CLLLPF', +'FATES_LBLAYER_COND_AP','FATES_STOMATAL_COND_AP' From 9be6081c736640ab2301e64d315428bf57b40212 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Wed, 29 May 2024 14:50:34 -0700 Subject: [PATCH 211/388] change how fates_hist_dimlevel is set Setting fates_hist_dimlevel with a single line (i.e. = 2,2) fails during ELMBuildNamelist. Adjust the assignment to accomodate this. This also removes hist_ndens to avoid issue #1106 --- .../testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm index 8ccaf9f5bb3..249764fb277 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/fates_cold_allvars/user_nl_elm @@ -2,9 +2,9 @@ hist_mfilt = 365 hist_nhtfrq = -24 hist_empty_htapes = .false. fates_spitfire_mode = 1 -fates_history_dimlevel = 2,2 +fates_history_dimlevel(1) = 2 +fates_history_dimlevel(2) = 2 use_fates_tree_damage = .true. -hist_ndens = 1 hist_fincl1 = 'FATES_TLONGTERM', 'FATES_TGROWTH','FATES_SEEDS_IN_GRIDCELL_PF','FATES_SEEDS_OUT_GRIDCELL_PF','FATES_NCL_AP', 'FATES_NPATCH_AP','FATES_VEGC_AP','FATES_SECONDAREA_ANTHRODIST_AP','FATES_SECONDAREA_DIST_AP', From 62fcccfbd2e66e5840916faf72e625e9c93b84ed Mon Sep 17 00:00:00 2001 From: Mathew Maltrud Date: Fri, 31 May 2024 10:43:21 -0500 Subject: [PATCH 212/388] replace global sum with full-precision reproducible sum --- .../mpas_ocn_tracer_surface_restoring.F | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F b/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F index f47608ef0d9..97e55b66087 100644 --- a/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F +++ b/components/mpas-ocean/src/shared/mpas_ocn_tracer_surface_restoring.F @@ -26,6 +26,7 @@ module ocn_tracer_surface_restoring use mpas_timekeeping use mpas_forcing use mpas_stream_manager + use mpas_global_sum_mod use ocn_constants use ocn_config use ocn_framework_forcing @@ -250,7 +251,11 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & integer :: ierr integer, parameter :: nSums = 2 - real (kind=RKIND), dimension(nSums) :: reductions, sums + real (kind=RKIND), dimension(nSums) :: reductions + + integer, dimension(nSums) :: indexForReproSum + real (kind=RKIND), dimension(:,:), allocatable :: & + localArrayForReproSum ! initialize monthly forcing to be read from file @@ -339,6 +344,9 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & call mpas_pool_get_array(forcingPool, 'landIceMask', landIceMask) call mpas_pool_get_array(meshPool, 'areaCell', areaCell) + allocate (localArrayForReproSum(nCellsSolve,2)) + localArrayForReproSum(:,:) = 0.0_RKIND + ! This is not in a threaded region, so no openMP pragmas are needed. if ( associated(landIceMask)) then @@ -414,11 +422,14 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & endif + indexForReproSum(1) = 1 + indexForReproSum(2) = 0 do iCell=1,nCellsSolve deltaS = activeTracersSurfaceRestoringValue(indexSalinitySurfaceRestoringValue,iCell) if (deltaS .ne. 0.0_RKIND) then - sumAreaDeltaS = sumAreaDeltaS + deltaS*areaCell(iCell) - sumArea = sumArea + areaCell(iCell) + indexForReproSum(2) = indexForReproSum(2) + 1 + localArrayForReproSum(indexForReproSum(2),1) = deltaS + localArrayForReproSum(indexForReproSum(2),2) = areaCell(iCell) endif enddo @@ -427,16 +438,18 @@ subroutine ocn_get_surfaceSalinityData( streamManager, & ! Global sum to subtract global mean of deltaS dminfo = domain % dminfo - sums(1) = sumAreaDeltaS - sums(2) = sumArea - call mpas_dmpar_sum_real_array(dminfo, nSums, sums(1:nSums), reductions(1:nSums)) - sumAreaDeltaSGlobal = reductions(1) - sumAreaGlobal = reductions(2) - avgDeltaS1 = sumAreaDeltaSGlobal/(sumAreaGlobal + 1.e-20_RKIND) - !LPV: There is no guarantee that a global sum of deltaS is BFB across - !decompositions, the next line rounds each value to 10 decimal places to - !ensure BFB results - avgDeltaS = float (int(avgDeltaS1 * 1.0E10_RKIND + 0.5_RKIND)) / 1.0E10_RKIND +! first do 1 field sum for area + reductions(1) = mpas_global_sum(localArrayForReproSum(:,2), & + domain%dminfo%comm, indexForReproSum) +! now do sum of 2 mupltiplied fields for area*deltaS + reductions(2) = mpas_global_sum(localArrayForReproSum(:,1), localArrayForReproSum(:,2), & + domain%dminfo%comm, indexForReproSum) + + sumAreaDeltaSGlobal = reductions(2) + sumAreaGlobal = reductions(1) + avgDeltaS = sumAreaDeltaSGlobal/(sumAreaGlobal + 1.e-20_RKIND) + + deallocate (localArrayForReproSum) block => domain % blocklist do while (associated(block)) From 73788b9a9d07a6758eb2307ba007ed6f93b07981 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 31 May 2024 10:48:15 -0500 Subject: [PATCH 213/388] Updates .gitmodules to zbgc-enabled icepack submodule branch --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 69d56e14036..c9d0b3dbad9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,6 +76,7 @@ [submodule "components/mpas-seaice/src/icepack"] path = components/mpas-seaice/src/icepack url = git@github.com:E3SM-Project/Icepack.git + branch = fixes-to-bgc-indices [submodule "externals/haero"] path = externals/haero url = git@github.com:eagles-project/haero.git From 393d0ed31f0ee64074949f47a137a03d88d510e4 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 31 May 2024 11:09:38 -0500 Subject: [PATCH 214/388] Reverts the previous commit --- .gitmodules | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index c9d0b3dbad9..69d56e14036 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,7 +76,6 @@ [submodule "components/mpas-seaice/src/icepack"] path = components/mpas-seaice/src/icepack url = git@github.com:E3SM-Project/Icepack.git - branch = fixes-to-bgc-indices [submodule "externals/haero"] path = externals/haero url = git@github.com:eagles-project/haero.git From 4873471b6aba3aceff6c808433a5e0d72b71486b Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Fri, 31 May 2024 12:08:35 -0500 Subject: [PATCH 215/388] Updating Icepack to hash #2e5d5a27 For BGC --- components/mpas-seaice/src/icepack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mpas-seaice/src/icepack b/components/mpas-seaice/src/icepack index abdd3d4bbc0..2e5d5a271ba 160000 --- a/components/mpas-seaice/src/icepack +++ b/components/mpas-seaice/src/icepack @@ -1 +1 @@ -Subproject commit abdd3d4bbc06255a3cdcff2d5c04ede90050eb51 +Subproject commit 2e5d5a271baf5d0705be76ac56fa588c9d7e252c From 2d05eb647d32a109f713f0183701bd09dcb3f909 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 4 Jun 2024 09:46:08 -0700 Subject: [PATCH 216/388] place expanded diagnostic write statement behind debug check --- components/elm/src/main/elmfates_interfaceMod.F90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/elm/src/main/elmfates_interfaceMod.F90 b/components/elm/src/main/elmfates_interfaceMod.F90 index bb8b8d93dc4..1b9d6c1ba49 100644 --- a/components/elm/src/main/elmfates_interfaceMod.F90 +++ b/components/elm/src/main/elmfates_interfaceMod.F90 @@ -661,10 +661,12 @@ subroutine CrossRefHistoryFields write(iulog,*) 'that does not contain that variable in its valid set.' write(iulog,*) 'You may have to increase the namelist setting: fates_history_dimlevel' write(iulog,*) 'current fates_history_dimlevel: ',fates_history_dimlevel(:) - !uncomment if you want to list all fates history variables in registry - !do_fates_hist2: do nh = 1,fates_hist%num_history_vars() - ! write(iulog,*) trim(fates_hist%hvars(nh)%vname) - !end do do_fates_hist2 + if (debug) then + !if you want to list all fates history variables in registry turn on debug + do_fates_hist2: do nh = 1,fates_hist%num_history_vars() + write(iulog,*) trim(fates_hist%hvars(nh)%vname) + end do do_fates_hist2 + end if call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if From a4f20f9747b145fb3777b113ffdedddb0accf07a Mon Sep 17 00:00:00 2001 From: Jon Wolfe Date: Tue, 4 Jun 2024 14:24:28 -0500 Subject: [PATCH 217/388] Add mapping and domain files for RRSwISC6to18E3r5 mesh --- cime_config/config_grids.xml | 173 +++++++++++++++++++++++++++++++---- 1 file changed, 157 insertions(+), 16 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index 7c8eb0ff75b..05ddf741d27 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -406,6 +406,16 @@ IcoswISC30E3r5 + + T62 + T62 + RRSwISC6to18E3r5 + rx1 + null + null + RRSwISC6to18E3r5 + + TL319 TL319 @@ -616,6 +626,16 @@ IcosXISC30E3r7 + + TL319 + TL319 + RRSwISC6to18E3r5 + JRA025 + null + null + RRSwISC6to18E3r5 + + TL319 TL319 @@ -1340,6 +1360,16 @@ IcoswISC30E3r5 + + ne30np4.pg2 + ne30np4.pg2 + RRSwISC6to18E3r5 + r05 + null + null + RRSwISC6to18E3r5 + + ne0np4_northamericax4v1 r0125 @@ -1623,6 +1653,26 @@ IcoswISC30E3r5 + + ne120np4.pg2 + r05 + RRSwISC6to18E3r5 + r05 + null + null + RRSwISC6to18E3r5 + + + + ne120np4.pg2 + r025 + RRSwISC6to18E3r5 + r025 + null + null + RRSwISC6to18E3r5 + + ne240np4 ne240np4 @@ -2291,6 +2341,16 @@ IcosXISC30E3r7 + + ne30np4.pg2 + r05 + RRSwISC6to18E3r5 + r05 + null + null + RRSwISC6to18E3r5 + + ne30np4.pg2 r05 @@ -2601,6 +2661,7 @@ $DIN_LOC_ROOT/share/domains/domain.lnd.T62_SOwISC12to60E2r4.210119.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_ECwISC30to60E2r1.201007.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_IcoswISC30E3r5.231121.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_RRSwISC6to18E3r5.240328.nc T62 is Gaussian grid: @@ -2657,6 +2718,8 @@ $DIN_LOC_ROOT/share/domains/domain.ocn.TL319_IcoswISC30E3r5.231121.nc $DIN_LOC_ROOT/share/domains/domain.lnd.TL319_IcosXISC30E3r7.240326.nc $DIN_LOC_ROOT/share/domains/domain.ocn.TL319_IcosXISC30E3r7.240326.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.TL319_RRSwISC6to18E3r5.240328.nc + $DIN_LOC_ROOT/share/domains/domain.ocn.TL319_RRSwISC6to18E3r5.240328.nc $DIN_LOC_ROOT/share/domains/domain.lnd.TL319_oRRS18to6v3.220124.nc $DIN_LOC_ROOT/share/domains/domain.ocn.TL319_oRRS18to6v3.220124.nc TL319 is JRA lat/lon grid: @@ -2768,6 +2831,8 @@ $DIN_LOC_ROOT/share/domains/domain.ocn.ne30pg2_IcoswISC30E3r5.231121.nc $DIN_LOC_ROOT/share/domains/domain.lnd.ne30pg2_IcosXISC30E3r7.240326.nc $DIN_LOC_ROOT/share/domains/domain.ocn.ne30pg2_IcosXISC30E3r7.240326.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.ne30pg2_RRSwISC6to18E3r5.240328.nc + $DIN_LOC_ROOT/share/domains/domain.ocn.ne30pg2_RRSwISC6to18E3r5.240328.nc $DIN_LOC_ROOT/share/domains/domain.lnd.ne30pg2_gx1v6.190806.nc $DIN_LOC_ROOT/share/domains/domain.ocn.ne30pg2_gx1v6.190806.nc ne30np4.pg2 is Spectral Elem 1-deg grid w/ 2x2 FV physics grid per element: @@ -2839,6 +2904,8 @@ $DIN_LOC_ROOT/share/domains/domain.ocn.ne120pg2_ICOS10.230120.nc $DIN_LOC_ROOT/share/domains/domain.lnd.ne120pg2_IcoswISC30E3r5.231121.nc $DIN_LOC_ROOT/share/domains/domain.ocn.ne120pg2_IcoswISC30E3r5.231121.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.ne120pg2_RRSwISC6to18E3r5.240328.nc + $DIN_LOC_ROOT/share/domains/domain.ocn.ne120pg2_RRSwISC6to18E3r5.240328.nc $DIN_LOC_ROOT/share/domains/domain.lnd.ne120pg2_gx1v6.190819.nc $DIN_LOC_ROOT/share/domains/domain.ocn.ne120pg2_gx1v6.190819.nc ne120np4 is Spectral Elem 1/4-deg grid w/ 2x2 FV physics grid @@ -3077,6 +3144,13 @@ IcosXISC30E3r7 is a MPAS ocean grid generated with the jigsaw/compass process using a dual mesh that is a subdivided icosahedron, resulting in a nearly uniform resolution of 30 km.: + + 4062533 + 1 + $DIN_LOC_ROOT/share/domains/domain.ocn.RRSwISC6to18E3r5.240328.nc + RRSwISC6to18E3r5 is a MPAS ocean grid generated with the jigsaw/compass process using a mesh density function that is roughly proportional to the Rossby radius of deformation, with 18 km gridcells at low and 6 km gridcells at high latitudes. Additionally, it has ocean in ice-shelf cavities: + + @@ -3111,6 +3185,8 @@ $DIN_LOC_ROOT/share/domains/domain.lnd.r05_IcoswISC30E3r5.231121.nc $DIN_LOC_ROOT/share/domains/domain.lnd.r05_IcosXISC30E3r7.240326.nc $DIN_LOC_ROOT/share/domains/domain.lnd.r05_IcosXISC30E3r7.240326.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.r05_RRSwISC6to18E3r5.240328.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.r05_RRSwISC6to18E3r5.240328.nc $DIN_LOC_ROOT/share/domains/domain.lnd.r05_gx1v6.191014.nc r05 is 1/2 degree river routing grid: @@ -3144,6 +3220,8 @@ 1440 720 $DIN_LOC_ROOT/share/domains/domain.lnd.r025_IcoswISC30E3r5.240129.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.r025_RRSwISC6to18E3r5.240328.nc + r025 is 1/4 degree river routing grid: @@ -3601,6 +3679,16 @@ cpl/gridmaps/ne30pg2/map_ne30pg2_to_IcosXISC30E3r7_trfvnp2.20240326.nc + + cpl/gridmaps/ne30pg2/map_ne30pg2_to_RRSwISC6to18E3r5_traave.20240328.nc + cpl/gridmaps/ne30pg2/map_ne30pg2_to_RRSwISC6to18E3r5_trbilin.20240328.nc + cpl/gridmaps/ne30pg2/map_ne30pg2_to_RRSwISC6to18E3r5-nomask_trbilin.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_ne30pg2_traave.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_ne30pg2_traave.20240328.nc + cpl/gridmaps/ne30pg2/map_ne30pg2_to_RRSwISC6to18E3r5_trfvnp2.20240328.nc + cpl/gridmaps/ne30pg2/map_ne30pg2_to_RRSwISC6to18E3r5_trfvnp2.20240328.nc + + cpl/gridmaps/ne30pg3/map_ne30pg3_to_oEC60to30v3_mono.200331.nc cpl/gridmaps/ne30pg3/map_ne30pg3_to_oEC60to30v3_bilin.200331.nc @@ -3676,6 +3764,14 @@ cpl/gridmaps/ne30pg4/map_r05_to_ne30pg4_mono.200331.nc + + cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_traave.20240206.nc + cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_trfv2.20240206.nc + cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_esmfbilin.20240206.nc + cpl/gridmaps/ne120pg2/map_r025_to_ne30pg2_traave.20240206.nc + cpl/gridmaps/ne120pg2/map_r025_to_ne30pg2_traave.20240206.nc + + cpl/gridmaps/ne30np4/map_ne30np4_to_r0125_mono.190801.nc cpl/gridmaps/ne30np4/map_ne30np4_to_r0125_mono.190801.nc @@ -3775,22 +3871,6 @@ cpl/gridmaps/ne120pg2/map_ne120pg2_to_r0125_mono.200707.nc - - cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_traave.20240206.nc - cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_trfv2.20240206.nc - cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_esmfbilin.20240206.nc - cpl/gridmaps/ne120pg2/map_r025_to_ne120pg2_traave.20240206.nc - cpl/gridmaps/ne120pg2/map_r025_to_ne120pg2_traave.20240206.nc - - - - cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_traave.20240206.nc - cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_trfv2.20240206.nc - cpl/gridmaps/ne120pg2/map_ne30pg2_to_r025_esmfbilin.20240206.nc - cpl/gridmaps/ne120pg2/map_r025_to_ne30pg2_traave.20240206.nc - cpl/gridmaps/ne120pg2/map_r025_to_ne30pg2_traave.20240206.nc - - cpl/gridmaps/ne120np4/map_ne120np4_to_oRRS18to6v3_mono.20200702.nc cpl/gridmaps/ne120np4/map_ne120np4_to_oRRS18to6v3_mono.20200702.nc @@ -3839,6 +3919,14 @@ cpl/gridmaps/IcoswISC30E3r5/map_IcoswISC30E3r5_to_ne120pg2_traave.20231121.nc + + cpl/gridmaps/ne120pg2/map_ne120pg2_to_RRSwISC6to18E3r5_traave.20240328.nc + cpl/gridmaps/ne120pg2/map_ne120pg2_to_RRSwISC6to18E3r5_trbilin.20240328.nc + cpl/gridmaps/ne120pg2/map_ne120pg2_to_RRSwISC6to18E3r5-nomask_trbilin.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_ne120pg2_traave.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_ne120pg2_traave.20240328.nc + + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r05_mono.200331.nc cpl/gridmaps/ne120pg2/map_ne120pg2_to_r05_bilin.200331.nc @@ -3846,11 +3934,24 @@ cpl/gridmaps/ne120pg2/map_r05_to_ne120pg2_mono.200331.nc + + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_traave.20240328.nc + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_trfv2.20240206.nc + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_trbilin.20240328.nc + cpl/gridmaps/ne120pg2/map_r025_to_ne120pg2_traave.20240328.nc + cpl/gridmaps/ne120pg2/map_r025_to_ne120pg2_trbilin.20240328.nc + + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r05_mono.200331.nc cpl/gridmaps/ne120pg2/map_ne120pg2_to_r05_bilin.200331.nc + + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_traave.20240328.nc + cpl/gridmaps/ne120pg2/map_ne120pg2_to_r025_trbilin.20240328.nc + + cpl/gridmaps/ne240np4/map_ne240np4_to_gx1v6_aave_110428.nc cpl/gridmaps/ne240np4/map_ne240np4_to_gx1v6_aave_110428.nc @@ -4368,6 +4469,14 @@ cpl/gridmaps/IcoswISC30E3r5/map_IcoswISC30E3r5_to_T62_traave.20231121.nc + + cpl/gridmaps/T62/map_T62_to_RRSwISC6to18E3r5_traave.20240328.nc + cpl/gridmaps/T62/map_T62_to_RRSwISC6to18E3r5-nomask_trbilin.20240328.nc + cpl/gridmaps/T62/map_T62_to_RRSwISC6to18E3r5_esmfpatch.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_T62_traave.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_T62_traave.20240328.nc + + cpl/gridmaps/TL319/map_TL319_to_oQU240wLI_traave.20240509.nc cpl/gridmaps/TL319/map_TL319_to_oQU240wLI-nomask_trbilin.20240509.nc @@ -4512,6 +4621,14 @@ cpl/gridmaps/IcosXISC30E3r7/map_IcosXISC30E3r7_to_TL319_traave.20240326.nc + + cpl/gridmaps/TL319/map_TL319_to_RRSwISC6to18E3r5_traave.20240328.nc + cpl/gridmaps/TL319/map_TL319_to_RRSwISC6to18E3r5-nomask_trbilin.20240328.nc + cpl/gridmaps/TL319/map_TL319_to_RRSwISC6to18E3r5_esmfpatch.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_TL319_traave.20240328.nc + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_TL319_traave.20240328.nc + + cpl/gridmaps/TL319/map_TL319_to_oRRS18to6v3_aave.220124.nc cpl/gridmaps/TL319/map_TL319_to_oRRS18to6v3_bilin.220124.nc @@ -4892,6 +5009,10 @@ cpl/gridmaps/IcosXISC30E3r7/map_IcosXISC30E3r7_to_r05_traave.20240326.nc + + cpl/gridmaps/RRSwISC6to18E3r5/map_RRSwISC6to18E3r5_to_r05_traave.20240328.nc + + cpl/cpl6/map_EC30to60E2r2_to_r05_neareststod.220728.nc @@ -5002,6 +5123,11 @@ cpl/cpl6/map_rx1_to_IcoswISC30E3r5_cstmnn.r150e300.20231121.nc + + cpl/cpl6/map_rx1_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + cpl/cpl6/map_rx1_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + + cpl/cpl6/map_JRA025_to_oQU240wLI_cstmnn.r150e300.20240516.nc cpl/cpl6/map_JRA025_to_oQU240wLI_cstmnn.r150e300.20240516.nc @@ -5092,6 +5218,11 @@ cpl/cpl6/map_JRA025_to_IcosXISC30E3r7_cstmnn.r150e300.20240326.nc + + cpl/cpl6/map_JRA025_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + cpl/cpl6/map_JRA025_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + + cpl/cpl6/map_JRA025_to_oRRS18to6v3_smoothed.r50e100.220124.nc cpl/cpl6/map_JRA025_to_oRRS18to6v3_smoothed.r50e100.220124.nc @@ -5182,11 +5313,21 @@ cpl/cpl6/map_r05_to_IcosXISC30E3r7_cstmnn.r150e300.20240326.nc + + cpl/cpl6/map_r05_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + cpl/cpl6/map_r05_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + + cpl/cpl6/map_r025_to_IcoswISC30E3r5_cstmnn.r150e300.20240401.nc cpl/cpl6/map_r025_to_IcoswISC30E3r5_cstmnn.r150e300.20240401.nc + + cpl/cpl6/map_r025_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + cpl/cpl6/map_r025_to_RRSwISC6to18E3r5_cstmnn.r50e100.20240328.nc + + cpl/cpl6/map_r0125_to_WC14to60E2r3_smoothed.r150e300.200929.nc cpl/cpl6/map_r0125_to_WC14to60E2r3_smoothed.r150e300.200929.nc From 565a93ead6085cf8a70a5efec68617bea2cff56f Mon Sep 17 00:00:00 2001 From: Jon Wolfe Date: Tue, 4 Jun 2024 14:59:09 -0500 Subject: [PATCH 218/388] Update mapping and domain files created with an incorrect T62 scrip file --- cime_config/config_grids.xml | 108 +++++++++++++++++------------------ 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index 7c8eb0ff75b..714727ad928 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -2581,16 +2581,16 @@ 96 $DIN_LOC_ROOT/share/domains/domain.lnd.T62_gx1v6.090320.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_gx3v7.090911.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU480.151209.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU240.151209.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU240wLI_mask.160929.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU120.151209.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oEC60to30v3.161222.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oEC60to30v3wLI_mask.170328.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU480.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU240.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU240wLI_mask.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oQU120.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oEC60to30v3.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oEC60to30v3wLI.240513.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_ECwISC30to60E1r2.200410.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS30to10v3.171129.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS30to10v3wLI_mask.171109.nc - $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS18to6v3.170111.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS30to10v3.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS30to10v3wLI.240513.nc + $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS18to6v3.240513.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oRRS15to5.150722.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oARRM60to10.180716.nc $DIN_LOC_ROOT/share/domains/domain.lnd.T62_oARRM60to6.180803.nc @@ -4209,51 +4209,51 @@ - cpl/gridmaps/T62/map_T62_TO_oQU480_aave.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU480_patc.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU480_blin.151209.nc - cpl/gridmaps/oQU480/map_oQU480_TO_T62_aave.151209.nc - cpl/gridmaps/oQU480/map_oQU480_TO_T62_aave.151209.nc + cpl/gridmaps/T62/map_T62_to_oQU480_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU480_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU480_esmfpatch.20240513.nc + cpl/gridmaps/oQU480/map_oQU480_to_T62_traave.20240513.nc + cpl/gridmaps/oQU480/map_oQU480_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oQU240_aave.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU240_patc.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU240_blin.151209.nc - cpl/gridmaps/oQU240/map_oQU240_TO_T62_aave.151209.nc - cpl/gridmaps/oQU240/map_oQU240_TO_T62_aave.151209.nc + cpl/gridmaps/T62/map_T62_to_oQU240_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU240_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU240_esmfpatch.20240513.nc + cpl/gridmaps/oQU240/map_oQU240_to_T62_traave.20240513.nc + cpl/gridmaps/oQU240/map_oQU240_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oQU240wLI_mask_aave.160929.nc - cpl/gridmaps/T62/map_T62_TO_oQU240wLI_nomask_aave.160929.nc - cpl/gridmaps/T62/map_T62_TO_oQU240wLI_mask_patc.160929.nc - cpl/gridmaps/oQU240wLI/map_oQU240wLI_mask_TO_T62_aave.160929.nc - cpl/gridmaps/oQU240wLI/map_oQU240wLI_mask_TO_T62_aave.160929.nc + cpl/gridmaps/T62/map_T62_to_oQU240wLI_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU240wLI-nomask_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU240wLI_esmfpatch.20240513.nc + cpl/gridmaps/oQU240wLI/map_oQU240wLI_to_T62_traave.20240513.nc + cpl/gridmaps/oQU240wLI/map_oQU240wLI_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oQU120_aave.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU120_patc.151209.nc - cpl/gridmaps/T62/map_T62_TO_oQU120_blin.151209.nc - cpl/gridmaps/oQU120/map_oQU120_TO_T62_aave.151209.nc - cpl/gridmaps/oQU120/map_oQU120_TO_T62_aave.151209.nc + cpl/gridmaps/T62/map_T62_to_oQU120_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU120_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oQU120_esmfpatch.20240513.nc + cpl/gridmaps/oQU120/map_oQU120_to_T62_traave.20240513.nc + cpl/gridmaps/oQU120/map_oQU120_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3_aave.161222.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3_blin.161222.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3_patc.161222.nc - cpl/gridmaps/oEC60to30v3/map_oEC60to30v3_TO_T62_aave.161222.nc - cpl/gridmaps/oEC60to30v3/map_oEC60to30v3_TO_T62_aave.161222.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3_esmfpatch.20240513.nc + cpl/gridmaps/oEC60to30v3/map_oEC60to30v3_to_T62_traave.20240513.nc + cpl/gridmaps/oEC60to30v3/map_oEC60to30v3_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3wLI_mask_aave.170328.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3wLI_nomask_blin.170328.nc - cpl/gridmaps/T62/map_T62_TO_oEC60to30v3wLI_mask_patc.170328.nc - cpl/gridmaps/oEC60to30v3wLI/map_oEC60to30v3wLI_mask_TO_T62_aave.170328.nc - cpl/gridmaps/oEC60to30v3wLI/map_oEC60to30v3wLI_mask_TO_T62_aave.170328.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3wLI_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3wLI-nomask_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oEC60to30v3wLI_esmfpatch.20240513.nc + cpl/gridmaps/oEC60to30v3wLI/map_oEC60to30v3wLI_to_T62_traave.20240513.nc + cpl/gridmaps/oEC60to30v3wLI/map_oEC60to30v3wLI_to_T62_traave.20240513.nc @@ -4265,27 +4265,27 @@ - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3_aave.171128.nc - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3_blin.171128.nc - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3_patc.171128.nc - cpl/gridmaps/oRRS30to10v3/map_oRRS30to10v3_TO_T62_aave.171128.nc - cpl/gridmaps/oRRS30to10v3/map_oRRS30to10v3_TO_T62_aave.171128.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3_esmfpatch.20240513.nc + cpl/gridmaps/oRRS30to10v3/map_oRRS30to10v3_to_T62_traave.20240513.nc + cpl/gridmaps/oRRS30to10v3/map_oRRS30to10v3_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3wLI_mask_aave.171109.nc - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3wLI_nomask_blin.171109.nc - cpl/gridmaps/T62/map_T62_TO_oRRS30to10v3wLI_mask_patc.171109.nc - cpl/gridmaps/oRRS30to10v3wLI/map_oRRS30to10v3wLI_mask_TO_T62_aave.171109.nc - cpl/gridmaps/oRRS30to10v3wLI/map_oRRS30to10v3wLI_mask_TO_T62_aave.171109.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3wLI_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3wLI-nomask_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS30to10v3wLI_esmfpatch.20240513.nc + cpl/gridmaps/oRRS30to10v3wLI/map_oRRS30to10v3wLI_to_T62_traave.20240513.nc + cpl/gridmaps/oRRS30to10v3wLI/map_oRRS30to10v3wLI_to_T62_traave.20240513.nc - cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_aave.170111.nc - cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_patc.170111.nc - cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_blin.170111.nc - cpl/gridmaps/oRRS18to6v3/map_oRRS18to6v3_to_T62_aave.170111.nc - cpl/gridmaps/oRRS18to6v3/map_oRRS18to6v3_to_T62_aave.170111.nc + cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_traave.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_trbilin.20240513.nc + cpl/gridmaps/T62/map_T62_to_oRRS18to6v3_esmfpatch.20240513.nc + cpl/gridmaps/oRRS18to6v3/map_oRRS18to6v3_to_T62_traave.20240513.nc + cpl/gridmaps/oRRS18to6v3/map_oRRS18to6v3_to_T62_traave.20240513.nc From bacb5048de8627e92178412ff335de0d5d3d4813 Mon Sep 17 00:00:00 2001 From: zyuying Date: Wed, 5 Jun 2024 13:52:58 -0700 Subject: [PATCH 219/388] Update cospsimulator_intr.F90 Change the longnames for all the joint-histogram variables to make them distinguishable. --- .../eam/src/physics/cam/cospsimulator_intr.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/eam/src/physics/cam/cospsimulator_intr.F90 b/components/eam/src/physics/cam/cospsimulator_intr.F90 index 663278e804c..dfc5491b909 100644 --- a/components/eam/src/physics/cam/cospsimulator_intr.F90 +++ b/components/eam/src/physics/cam/cospsimulator_intr.F90 @@ -1062,22 +1062,22 @@ subroutine cospsimulator_intr_init() call addfld ('CLMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & flag_xyfill=.true., fill_value=R_UNDEF) ! float clliqmodis ( time, plev, tau, loc ) - call addfld ('CLLIQMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('CLLIQMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud-top Pressure vs Cloud Optical Thickness for Liquid-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) ! float clicemodis ( time, plev, tau, loc ) - call addfld ('CLICEMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('CLICEMODIS',(/'cosp_tau_modis','cosp_prs '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud-top Pressure vs Cloud Optical Thickness for Ice-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) ! float clrimodis ( time, plev, tau, loc ) - call addfld ('CLRIMODIS',(/'cosp_tau_modis','cosp_reffice '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('CLRIMODIS',(/'cosp_tau_modis','cosp_reffice '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud Optical Thickness vs Cloud Particle Size for Ice-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) ! float clrlmodis ( time, plev, tau, loc ) - call addfld ('CLRLMODIS',(/'cosp_tau_modis','cosp_reffliq '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('CLRLMODIS',(/'cosp_tau_modis','cosp_reffliq '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud Optical Thickness vs Cloud Particle Size for Liquid-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) ! float iwprimodis ( time, reffice, iwp, loc ) - call addfld ('IWPRIMODIS',(/'cosp_iwp_modis','cosp_reffice '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('IWPRIMODIS',(/'cosp_iwp_modis','cosp_reffice '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud Water Path vs Cloud Particle Size for Ice-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) ! float lwprlmodis ( time, reffliq, lwp, loc ) - call addfld ('LWPRLMODIS',(/'cosp_lwp_modis','cosp_reffliq '/),'A','%','MODIS Cloud Area Fraction', & + call addfld ('LWPRLMODIS',(/'cosp_lwp_modis','cosp_reffliq '/),'A','%','MODIS Cloud-Fraction Joint Histogram of Cloud Water Path vs Cloud Particle Size for Liquid-topped Clouds', & flag_xyfill=.true., fill_value=R_UNDEF) !! add MODIS output to history file specified by the CAM namelist variable cosp_histfile_num From b103205b40933fcb7b19e74be4d5cd9a5ed82c3e Mon Sep 17 00:00:00 2001 From: Youngsung Kim Date: Sun, 2 Jun 2024 10:27:12 -0400 Subject: [PATCH 220/388] Matches Nvidia GPU compute capability (CC) version to cc80 on Perlmutter-GPU. --- cime_config/machines/cmake_macros/nvidiagpu_pm-gpu.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/cmake_macros/nvidiagpu_pm-gpu.cmake b/cime_config/machines/cmake_macros/nvidiagpu_pm-gpu.cmake index 59758d59989..852483663a0 100644 --- a/cime_config/machines/cmake_macros/nvidiagpu_pm-gpu.cmake +++ b/cime_config/machines/cmake_macros/nvidiagpu_pm-gpu.cmake @@ -6,8 +6,8 @@ if (COMP_NAME STREQUAL gptl) endif() string(APPEND CPPDEFS " -DTHRUST_IGNORE_CUB_VERSION_CHECK") string(APPEND CMAKE_CUDA_FLAGS " -ccbin CC -O2 -arch sm_80 --use_fast_math") -string(APPEND CMAKE_EXE_LINKER_FLAGS " -acc -gpu=cc70,cc60 -Minfo=accel") +string(APPEND CMAKE_EXE_LINKER_FLAGS " -acc -gpu=cc80 -Minfo=accel") set(SCC "cc") set(SCXX "CC") set(SFC "ftn") -string(APPEND CMAKE_Fortran_FLAGS " -acc -gpu=cc70,cc60 -Minfo=accel") +string(APPEND CMAKE_Fortran_FLAGS " -acc -gpu=cc80 -Minfo=accel") From e6e4fb7bb4d1bccfd65e096c31edc3a4b28500b1 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 6 Jun 2024 15:39:18 -0400 Subject: [PATCH 221/388] remove line --- components/eam/src/physics/crm/pam/pam_state.h | 1 - 1 file changed, 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/pam_state.h b/components/eam/src/physics/crm/pam/pam_state.h index 270fef7f6c2..980fb7f4eb0 100644 --- a/components/eam/src/physics/crm/pam/pam_state.h +++ b/components/eam/src/physics/crm/pam/pam_state.h @@ -156,7 +156,6 @@ inline void pam_state_set_reference_state( pam::PamCoupler &coupler ) { parallel_for(SimpleBounds<2>(nz+1,nens), YAKL_LAMBDA (int k, int iens) { hmean_pint(k,iens) = 0; if (k < nz) { - hmean_pmid (k,iens) = 0; hmean_rho_d(k,iens) = 0; hmean_rho_v(k,iens) = 0; hmean_rho_c(k,iens) = 0; From 30faaba50681d0821a80ccb9b5592c9d81b6074e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 6 Jun 2024 15:39:41 -0400 Subject: [PATCH 222/388] make variables const --- .../eam/src/physics/crm/pam/pam_variance_transport.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_variance_transport.h b/components/eam/src/physics/crm/pam/pam_variance_transport.h index 1eb7779f346..70b985cc2b7 100644 --- a/components/eam/src/physics/crm/pam/pam_variance_transport.h +++ b/components/eam/src/physics/crm/pam/pam_variance_transport.h @@ -36,11 +36,11 @@ inline void pam_variance_transport_diagnose( pam::PamCoupler &coupler ) { auto ny = coupler.get_option("crm_ny"); auto nx = coupler.get_option("crm_nx"); //------------------------------------------------------------------------------------------------ - auto temp = dm_device.get("temp" ); - auto rhov = dm_device.get("water_vapor"); - auto rhoc = dm_device.get("cloud_water"); - auto rhoi = dm_device.get("ice" ); - auto uvel = dm_device.get("uvel" ); + auto temp = dm_device.get("temp" ); + auto rhov = dm_device.get("water_vapor"); + auto rhoc = dm_device.get("cloud_water"); + auto rhoi = dm_device.get("ice" ); + auto uvel = dm_device.get("uvel" ); auto vt_temp = dm_device.get("vt_temp" ); auto vt_rhov = dm_device.get("vt_rhov" ); auto vt_uvel = dm_device.get("vt_uvel" ); From f9e6cc20fbe98699adcbae004932871bf198c943 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 6 Jun 2024 15:40:13 -0400 Subject: [PATCH 223/388] switch to std::abs --- components/eam/src/physics/crm/pam/pam_driver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index f8f575ec8a1..bed8980ea67 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -61,8 +61,8 @@ inline int pam_driver_set_subcycle_timestep( pam::PamCoupler &coupler, real crm_ }); // calculate max U and W parallel_for( SimpleBounds<4>(crm_nz,crm_ny,crm_nx,nens) , YAKL_LAMBDA (int k, int j, int i, int n) { - yakl::atomicMax(uvel_max(k,n), sqrt(uvel(k,j,i,n)*uvel(k,j,i,n)) ); - yakl::atomicMax(wvel_max(k,n), fabs(wvel(k,j,i,n)) ); + yakl::atomicMax(uvel_max(k,n), std::abs(uvel(k,j,i,n)) ); + yakl::atomicMax(wvel_max(k,n), std::abs(wvel(k,j,i,n)) ); }); // find max CFL between horizontal and vertical CFL values parallel_for( SimpleBounds<2>(crm_nz,nens) , YAKL_LAMBDA (int k, int n) { From 2590f226f43c316ecb224649c00e597a7dce8b43 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 6 Jun 2024 15:42:58 -0400 Subject: [PATCH 224/388] remove pmax --- components/eam/src/physics/crm/pam/pam_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/crm/pam/pam_driver.cpp b/components/eam/src/physics/crm/pam/pam_driver.cpp index bed8980ea67..5fd1c5071d1 100644 --- a/components/eam/src/physics/crm/pam/pam_driver.cpp +++ b/components/eam/src/physics/crm/pam/pam_driver.cpp @@ -73,7 +73,7 @@ inline int pam_driver_set_subcycle_timestep( pam::PamCoupler &coupler, real crm_ cfl_max(k,n) = max(cfl_u,cfl_w); }); // calculate final CFL across ensemble - real cfl_loc = pmax(cfl_max.data()); + real cfl_loc = yakl::intrinsics::maxval(cfl_max); cfl = max(cfl,cfl_loc); // update number of subcycles and time step num_subcycle = max(num_subcycle,max(1,static_cast(ceil(cfl/0.7)))); From 11ae9ce7203239dd377b248df9011d1747dc2d91 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 6 Apr 2024 09:19:57 -0500 Subject: [PATCH 225/388] Disable reading land-ice topography from lat-lon file We do not use this mode anymore and it is too difficult to maintain. --- .../src/mode_init/Registry_global_ocean.xml | 40 --- .../mode_init/mpas_ocn_init_global_ocean.F | 263 +----------------- 2 files changed, 9 insertions(+), 294 deletions(-) diff --git a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml index 0ef1ff95245..6018b182136 100644 --- a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml +++ b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml @@ -199,46 +199,6 @@ description="Logical flag that controls if sea surface pressure and layer thicknesses should be altered by an overlying ice sheet/shelf." possible_values=".true. or .false." /> - - - - - - - - - - \brief Read the ice sheet thickness IC file -!> \author Jeremy Fyke, Xylar Asay-Davis, Mark Petersen (modified from Doug Jacobsen code) -!> \date 06/15/2015 -!> \details -!> This routine reads the ice sheet topography IC file, including latitude and longitude -!> information for ice sheet topography data. -! -!----------------------------------------------------------------------- - - subroutine ocn_init_setup_global_ocean_read_land_ice_topography(domain, iErr)!{{{ - type (domain_type), intent(inout) :: domain - integer, intent(out) :: iErr - - type (MPAS_Stream_type) :: landIceThicknessStream - - iErr = 0 - - ! Define stream for depth levels - call MPAS_createStream(landIceThicknessStream, domain % iocontext, config_global_ocean_land_ice_topo_file, & - MPAS_IO_NETCDF, MPAS_IO_READ, ierr=iErr) - - ! Setup landIceThkLat, landIceThkLon, and landIceThkIC fields for stream to be read in - landIceThkLat % fieldName = trim(config_global_ocean_land_ice_topo_lat_varname) - landIceThkLat % dimSizes(1) = nLatLandIceThk - landIceThkLat % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlat_dimname) - landIceThkLat % isVarArray = .false. - landIceThkLat % isPersistent = .true. - landIceThkLat % isActive = .true. - landIceThkLat % hasTimeDimension = .false. - landIceThkLat % block => domain % blocklist - allocate(landIceThkLat % attLists(1)) - allocate(landIceThkLat % array(nLatLandIceThk)) - - landIceThkLon % fieldName = trim(config_global_ocean_land_ice_topo_lon_varname) - landIceThkLon % dimSizes(1) = nLonLandIceThk - landIceThkLon % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlon_dimname) - landIceThkLon % isVarArray = .false. - landIceThkLon % isPersistent = .true. - landIceThkLon % isActive = .true. - landIceThkLon % hasTimeDimension = .false. - landIceThkLon % block => domain % blocklist - allocate(landIceThkLon % attLists(1)) - allocate(landIceThkLon % array(nLonLandIceThk)) - - landIceThkIC % fieldName = trim(config_global_ocean_land_ice_topo_thickness_varname) - landIceThkIC % dimSizes(1) = nLonLandIceThk - landIceThkIC % dimSizes(2) = nLatLandIceThk - landIceThkIC % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlon_dimname) - landIceThkIC % dimNames(2) = trim(config_global_ocean_land_ice_topo_nlat_dimname) - landIceThkIC % isVarArray = .false. - landIceThkIC % isPersistent = .true. - landIceThkIC % isActive = .true. - landIceThkIC % hasTimeDimension = .false. - landIceThkIC % block => domain % blocklist - allocate(landIceThkIC % attLists(1)) - allocate(landIceThkIC % array(nLonLandIceThk, nLatLandIceThk)) - - landIceDraftIC % fieldName = trim(config_global_ocean_land_ice_topo_draft_varname) - landIceDraftIC % dimSizes(1) = nLonLandIceThk - landIceDraftIC % dimSizes(2) = nLatLandIceThk - landIceDraftIC % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlon_dimname) - landIceDraftIC % dimNames(2) = trim(config_global_ocean_land_ice_topo_nlat_dimname) - landIceDraftIC % isVarArray = .false. - landIceDraftIC % isPersistent = .true. - landIceDraftIC % isActive = .true. - landIceDraftIC % hasTimeDimension = .false. - landIceDraftIC % block => domain % blocklist - allocate(landIceDraftIC % attLists(1)) - allocate(landIceDraftIC % array(nLonLandIceThk, nLatLandIceThk)) - - landIceFracIC % fieldName = trim(config_global_ocean_land_ice_topo_ice_frac_varname) - landIceFracIC % dimSizes(1) = nLonLandIceThk - landIceFracIC % dimSizes(2) = nLatLandIceThk - landIceFracIC % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlon_dimname) - landIceFracIC % dimNames(2) = trim(config_global_ocean_land_ice_topo_nlat_dimname) - landIceFracIC % isVarArray = .false. - landIceFracIC % isPersistent = .true. - landIceFracIC % isActive = .true. - landIceFracIC % hasTimeDimension = .false. - landIceFracIC % block => domain % blocklist - allocate(landIceFracIC % attLists(1)) - allocate(landIceFracIC % array(nLonLandIceThk, nLatLandIceThk)) - - groundedFracIC % fieldName = trim(config_global_ocean_land_ice_topo_grounded_frac_varname) - groundedFracIC % dimSizes(1) = nLonLandIceThk - groundedFracIC % dimSizes(2) = nLatLandIceThk - groundedFracIC % dimNames(1) = trim(config_global_ocean_land_ice_topo_nlon_dimname) - groundedFracIC % dimNames(2) = trim(config_global_ocean_land_ice_topo_nlat_dimname) - groundedFracIC % isVarArray = .false. - groundedFracIC % isPersistent = .true. - groundedFracIC % isActive = .true. - groundedFracIC % hasTimeDimension = .false. - groundedFracIC % block => domain % blocklist - allocate(groundedFracIC % attLists(1)) - allocate(groundedFracIC % array(nLonLandIceThk, nLatLandIceThk)) - - ! Add landIceThkLat, landIceThkLon, and landIceThkIC fields to stream - call MPAS_streamAddField(landIceThicknessStream, landIceThkLat, iErr) - call MPAS_streamAddField(landIceThicknessStream, landIceThkLon, iErr) - call MPAS_streamAddField(landIceThicknessStream, landIceThkIC, iErr) - call MPAS_streamAddField(landIceThicknessStream, landIceDraftIC, iErr) - call MPAS_streamAddField(landIceThicknessStream, landIceFracIC, iErr) - call MPAS_streamAddField(landIceThicknessStream, groundedFracIC, iErr) - - ! Read stream - call MPAS_readStream(landIceThicknessStream, 1, iErr) - - ! Close stream - call MPAS_closeStream(landIceThicknessStream) - - if (config_global_ocean_land_ice_topo_latlon_degrees) then - landIceThkLat % array(:) = landIceThkLat % array(:) * pii / 180.0_RKIND - landIceThkLon % array(:) = landIceThkLon % array(:) * pii / 180.0_RKIND - end if - - end subroutine ocn_init_setup_global_ocean_read_land_ice_topography!}}} - !*********************************************************************** ! ! routine ocn_init_setup_global_ocean_create_model_topo @@ -1089,76 +958,6 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i iErr = 0 - if (config_global_ocean_topography_source == "latlon_file") then - block_ptr => domain % blocklist - do while(associated(block_ptr)) - - call mpas_pool_get_subpool(block_ptr % structs, 'mesh', meshPool) - call mpas_pool_get_subpool(block_ptr % structs, 'landIceInit', landIceInitPool) - call mpas_pool_get_dimension(meshPool, 'nCells', nCells) - - call mpas_pool_get_array(meshPool, 'latCell', latCell) - call mpas_pool_get_array(meshPool, 'lonCell', lonCell) - call mpas_pool_get_array(landIceInitPool, 'landIceDraftObserved', landIceDraftObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceThkObserved', landIceThkObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFracObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceGroundedFracObserved', landIceGroundedFracObserved) - - if (config_global_ocean_topography_method .eq. "nearest_neighbor") then - - call ocn_init_interpolation_nearest_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceThkIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceThkObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_nearest_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceDraftIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceDraftObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_nearest_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceFracIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceFracObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_nearest_horiz(landIceThkLon % array, landIceThkLat % array, & - groundedFracIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceGroundedFracObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - elseif (config_global_ocean_topography_method .eq. "bilinear_interpolation") then - - call ocn_init_interpolation_bilinear_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceThkIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceThkObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_bilinear_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceDraftIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceDraftObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_bilinear_horiz(landIceThkLon % array, landIceThkLat % array, & - landIceFracIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceFracObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - call ocn_init_interpolation_bilinear_horiz(landIceThkLon % array, landIceThkLat % array, & - groundedFracIC % array, nLonLandIceThk, nLatLandIceThk, & - lonCell, latCell, landIceGroundedFracObserved, nCells, & - inXPeriod = 2.0_RKIND * pii) - - else - call mpas_log_write( 'Invalid choice of config_global_ocean_topography_method.', MPAS_LOG_CRIT) - iErr = 1 - call mpas_dmpar_finalize(domain % dminfo) - endif - - block_ptr => block_ptr % next - end do - end if - - ! Iteratively smooth landIceDraftObserved, landIceThkObserved, landIceFracObserved, ! and landIceGroundedFracObserved before using them to adjust SSH, compute ! land-ice pressure, etc. @@ -2727,26 +2526,6 @@ subroutine ocn_init_global_ocean_destroy_topo_fields()!{{{ deallocate(topoLon % array) end subroutine ocn_init_global_ocean_destroy_topo_fields!}}} -!*********************************************************************** -! -! routine ocn_init_global_ocean_destroy_land_ice_topography_fields -! -!> \brief Topography field cleanup routine -!> \author Jeremy Fyke, Xylar Asay-Davis, Mark Petersen -!> \date 06/23/2015 -!> \details -!> This routine destroys the fields created to hold land ice topography -!> initial condition information -! -!----------------------------------------------------------------------- - - subroutine ocn_init_global_ocean_destroy_land_ice_topography_fields()!{{{ - deallocate(landIceThkIC % array) - deallocate(landIceDraftIC % array) - deallocate(landIceThkLat % array) - deallocate(landIceThkLon % array) - end subroutine ocn_init_global_ocean_destroy_land_ice_topography_fields!}}} - !*********************************************************************** ! ! routine ocn_init_global_ocean_destroy_windstress_fields @@ -2841,9 +2620,6 @@ subroutine ocn_init_validate_global_ocean(configPool, packagePool, iocontext, iE config_global_ocean_windstress_file, & config_global_ocean_windstress_nlat_dimname, & config_global_ocean_windstress_nlon_dimname, & - config_global_ocean_land_ice_topo_file, & - config_global_ocean_land_ice_topo_nlat_dimname, & - config_global_ocean_land_ice_topo_nlon_dimname, & config_global_ocean_swData_file, & config_global_ocean_swData_nlon_dimname, & config_global_ocean_swData_nlat_dimname, & @@ -2895,12 +2671,6 @@ subroutine ocn_init_validate_global_ocean(configPool, packagePool, iocontext, iE config_global_ocean_depress_by_land_ice) call mpas_pool_get_config(configPool, 'config_use_ecosysTracers', & config_use_ecosysTracers) - call mpas_pool_get_config(configPool, 'config_global_ocean_land_ice_topo_file', & - config_global_ocean_land_ice_topo_file) - call mpas_pool_get_config(configPool, 'config_global_ocean_land_ice_topo_nlat_dimname', & - config_global_ocean_land_ice_topo_nlat_dimname) - call mpas_pool_get_config(configPool, 'config_global_ocean_land_ice_topo_nlon_dimname', & - config_global_ocean_land_ice_topo_nlon_dimname) call mpas_pool_get_config(configPool, 'config_global_ocean_deepen_critical_passages', & config_global_ocean_deepen_critical_passages) call mpas_pool_get_config(configPool, 'config_global_ocean_windstress_file', & @@ -3018,6 +2788,14 @@ subroutine ocn_init_validate_global_ocean(configPool, packagePool, iocontext, iE return end if + if (config_global_ocean_topography_source == 'latlon_file' .and. & + config_global_ocean_depress_by_land_ice) then + call mpas_log_write( 'Land ice topography can no longer be read from ' & + // 'a lat-lon file', MPAS_LOG_CRIT) + iErr = 1 + return + end if + if (config_global_ocean_topography_source == 'latlon_file') then inputFile = MPAS_io_open(config_global_ocean_topography_file, MPAS_IO_READ, MPAS_IO_NETCDF, iocontext_ptr, ierr=iErr) if (iErr /= 0) then @@ -3076,29 +2854,6 @@ subroutine ocn_init_validate_global_ocean(configPool, packagePool, iocontext, iE end if - if (config_global_ocean_depress_by_land_ice) then - if (config_global_ocean_land_ice_topo_file == 'none' .and. & - config_global_ocean_topography_source == 'latlon_file') then - call mpas_log_write( 'Validation failed for global ocean. '// & - 'Invalid filename for config_global_ocean_land_ice_topo_file', MPAS_LOG_CRIT) - iErr = 1 - return - end if - - if(config_global_ocean_topography_source == 'latlon_file') then - inputFile = MPAS_io_open(config_global_ocean_land_ice_topo_file, MPAS_IO_READ, MPAS_IO_NETCDF, iocontext_ptr, ierr=iErr) - if (iErr /= 0) then - call mpas_log_write( 'could not open file '// trim(config_global_ocean_land_ice_topo_file), MPAS_LOG_CRIT) - return - end if - - call MPAS_io_inq_dim(inputFile, config_global_ocean_land_ice_topo_nlat_dimname, nLatLandIceThk, iErr) - call MPAS_io_inq_dim(inputFile, config_global_ocean_land_ice_topo_nlon_dimname, nLonLandIceThk, iErr) - - call MPAS_io_close(inputFile, iErr) - end if - end if - !-------------------------------------------------------------------- end subroutine ocn_init_validate_global_ocean!}}} From e8363b88a263d9efe52da0cc9ebcbdc9d3c477ac Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 6 Apr 2024 09:46:12 -0500 Subject: [PATCH 226/388] Read topo variable landIcePressureObserved --- .../mpas-ocean/src/mode_init/Registry_global_ocean.xml | 3 +++ .../src/mode_init/mpas_ocn_init_global_ocean.F | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml index 6018b182136..d2120d9f975 100644 --- a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml +++ b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml @@ -357,6 +357,9 @@ + diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F index 92d94c474b1..ef80ba69e02 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F @@ -942,7 +942,9 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i statePool real (kind=RKIND), dimension(:), pointer :: latCell, lonCell - real (kind=RKIND), dimension(:), pointer :: landIceThkObserved, landIceDraftObserved, & + real (kind=RKIND), dimension(:), pointer :: landIceThkObserved, & + landIceDraftObserved, & + landIcePressureObserved, & landIceFracObserved, & landIceFloatingFracObserved, & landIceGroundedFracObserved @@ -965,6 +967,10 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i config_global_ocean_topography_smooth_iterations, & config_global_ocean_topography_smooth_weight) + call ocn_init_smooth_field(domain, 'landIcePressureObserved', 'landIceInit', & + config_global_ocean_topography_smooth_iterations, & + config_global_ocean_topography_smooth_weight) + call ocn_init_smooth_field(domain, 'landIceThkObserved', 'landIceInit', & config_global_ocean_topography_smooth_iterations, & config_global_ocean_topography_smooth_weight) @@ -988,6 +994,7 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i call mpas_pool_get_array(meshPool, 'maxLevelCell', maxLevelCell) call mpas_pool_get_array(landIceInitPool, 'landIceDraftObserved', landIceDraftObserved) + call mpas_pool_get_array(landIceInitPool, 'landIcePressureObserved', landIcePressureObserved) call mpas_pool_get_array(landIceInitPool, 'landIceThkObserved', landIceThkObserved) call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFracObserved) call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFloatingFracObserved) From 46fcffe2367702278794525fda5e888d8c33955f Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 6 Apr 2024 10:11:04 -0500 Subject: [PATCH 227/388] Use land-ice topography from file This merge uses the `landIceDraftObserved`, `landIcePressureObserved` and `landIceFloatingFracObserved` to initialize the corresponding MPAS-Ocean variables. Previously, the `landIcePressure` was being computed in a subroutine and the `landIceFloatingFraction` was required to be identical to `landIceFraction`. This merge also removes the unused variable `landIceGroundedFracObserved` --- .../src/mode_init/Registry_global_ocean.xml | 6 +- .../mode_init/mpas_ocn_init_global_ocean.F | 83 +++++++------------ 2 files changed, 35 insertions(+), 54 deletions(-) diff --git a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml index d2120d9f975..3e3d6e9e479 100644 --- a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml +++ b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml @@ -136,7 +136,7 @@ possible_values="Any real positive number." /> - diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F index ef80ba69e02..4a505b5b2be 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F @@ -37,7 +37,6 @@ module ocn_init_global_ocean use ocn_init_cell_markers use ocn_init_vertical_grids use ocn_init_interpolation - use ocn_init_ssh_and_landIcePressure use ocn_init_smoothing implicit none @@ -491,21 +490,9 @@ subroutine ocn_init_setup_global_ocean(domain, iErr)!{{{ if (config_global_ocean_depress_by_land_ice) then call mpas_log_write('Modifying temperature and surface restoring under land ice.') call ocn_init_setup_global_ocean_modify_temp_under_land_ice(domain, iErr) - - call mpas_log_write('Calculating land-ice pressure from the weight of ice shelves') - ! compute the land-ice pressure, also computing density along the way. - call ocn_init_ssh_and_landIcePressure_balance(domain, iErr) - - if(iErr .ne. 0) then - call mpas_log_write( 'ocn_init_ssh_and_landIcePressure_balance failed.', MPAS_LOG_CRIT) - call mpas_dmpar_finalize(domain % dminfo) - end if - end if call mpas_log_write( 'Copying restoring fields') - ! this occurs after ocn_init_ssh_and_landIcePressure_balance because activeTracers may have been remapped - ! to a new vertical coordinate call ocn_init_setup_global_ocean_interpolate_restoring(domain, iErr) call mpas_log_write( 'Compute Haney number') @@ -942,16 +929,16 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i statePool real (kind=RKIND), dimension(:), pointer :: latCell, lonCell - real (kind=RKIND), dimension(:), pointer :: landIceThkObserved, & - landIceDraftObserved, & + real (kind=RKIND), dimension(:), pointer :: landIceDraftObserved, & landIcePressureObserved, & landIceFracObserved, & - landIceFloatingFracObserved, & - landIceGroundedFracObserved + landIceFloatingFracObserved - real (kind=RKIND), dimension(:), pointer :: landIcePressure, landIceFraction, & - landIceFloatingFraction, ssh, & - bottomDepth + real (kind=RKIND), dimension(:), pointer :: landIceDraft, & + landIcePressure, & + landIceFraction, & + landIceFloatingFraction, & + ssh integer, pointer :: nCells integer, dimension(:), pointer :: maxLevelCell, landIceMask, landIceFloatingMask @@ -960,28 +947,24 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i iErr = 0 - ! Iteratively smooth landIceDraftObserved, landIceThkObserved, landIceFracObserved, - ! and landIceGroundedFracObserved before using them to adjust SSH, compute - ! land-ice pressure, etc. - call ocn_init_smooth_field(domain, 'landIceDraftObserved', 'landIceInit', & - config_global_ocean_topography_smooth_iterations, & - config_global_ocean_topography_smooth_weight) - - call ocn_init_smooth_field(domain, 'landIcePressureObserved', 'landIceInit', & - config_global_ocean_topography_smooth_iterations, & - config_global_ocean_topography_smooth_weight) + ! Iteratively smooth land ice topography variables + if (config_global_ocean_topography_smooth_weight > 0) then + call ocn_init_smooth_field(domain, 'landIceDraftObserved', 'landIceInit', & + config_global_ocean_topography_smooth_iterations, & + config_global_ocean_topography_smooth_weight) - call ocn_init_smooth_field(domain, 'landIceThkObserved', 'landIceInit', & - config_global_ocean_topography_smooth_iterations, & - config_global_ocean_topography_smooth_weight) + call ocn_init_smooth_field(domain, 'landIcePressureObserved', 'landIceInit', & + config_global_ocean_topography_smooth_iterations, & + config_global_ocean_topography_smooth_weight) - call ocn_init_smooth_field(domain, 'landIceFracObserved', 'landIceInit', & - config_global_ocean_topography_smooth_iterations, & - config_global_ocean_topography_smooth_weight) + call ocn_init_smooth_field(domain, 'landIceFracObserved', 'landIceInit', & + config_global_ocean_topography_smooth_iterations, & + config_global_ocean_topography_smooth_weight) - call ocn_init_smooth_field(domain, 'landIceGroundedFracObserved', 'landIceInit', & - config_global_ocean_topography_smooth_iterations, & - config_global_ocean_topography_smooth_weight) + call ocn_init_smooth_field(domain, 'landIceFloatingFracObserved', 'landIceInit', & + config_global_ocean_topography_smooth_iterations, & + config_global_ocean_topography_smooth_weight) + end if block_ptr => domain % blocklist do while(associated(block_ptr)) @@ -995,13 +978,12 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i call mpas_pool_get_array(meshPool, 'maxLevelCell', maxLevelCell) call mpas_pool_get_array(landIceInitPool, 'landIceDraftObserved', landIceDraftObserved) call mpas_pool_get_array(landIceInitPool, 'landIcePressureObserved', landIcePressureObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceThkObserved', landIceThkObserved) call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFracObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFloatingFracObserved) - call mpas_pool_get_array(landIceInitPool, 'landIceGroundedFracObserved', landIceGroundedFracObserved) + call mpas_pool_get_array(landIceInitPool, 'landIceFloatingFracObserved', landIceFloatingFracObserved) call mpas_pool_get_array(statePool, 'ssh', ssh, 1) call mpas_pool_get_array(forcingPool, 'landIceMask', landIceMask) call mpas_pool_get_array(forcingPool, 'landIceFloatingMask', landIceFloatingMask) + call mpas_pool_get_array(forcingPool, 'landIceDraft', landIceDraft) call mpas_pool_get_array(forcingPool, 'landIcePressure', landIcePressure) call mpas_pool_get_array(forcingPool, 'landIceFraction', landIceFraction) call mpas_pool_get_array(forcingPool, 'landIceFloatingFraction', landIceFloatingFraction) @@ -1013,26 +995,25 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i endif ssh(:) = 0.0_RKIND landIceFraction(:) = 0.0_RKIND - modifyLandIcePressureMask(:) = 0 + landIceDraft(:) = 0.0_RKIND landIcePressure(:) = 0.0_RKIND + modifyLandIcePressureMask(:) = 0 do iCell = 1, nCells + ! nothing to do here if the cell is land + if (maxLevelCell(iCell) <= 0) cycle if (landIceMask(iCell) == 1) then landIceFraction(iCell) = landIceFracObserved(iCell) end if - ! this implicitly assumes that when a cell is considered floating, the - ! full landIceFracObserved is floating if (landIceFloatingMask(iCell) == 1) then landIceFloatingFraction(iCell) = landIceFloatingFracObserved(iCell) end if - ! nothing to do here if the cell is land - if (maxLevelCell(iCell) <= 0) cycle - - ! we compute the SSH first and find out the land-ice pressure - ssh(iCell) = min(0.0_RKIND, landIceDraftObserved(iCell)) - if (ssh(iCell) < 0.0_RKIND) then + landIceDraft(iCell) = landIceDraftObserved(iCell) + ssh(iCell) = landIceDraft(iCell) + landIcePressure(iCell) = landIcePressureObserved(iCell) + if (landIcePressure(iCell) > 0.0_RKIND) then modifyLandIcePressureMask(iCell) = 1 end if end do From f37233106eca0c418e7e7a231a2b9207c9c9a5eb Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 8 Apr 2024 07:01:46 -0500 Subject: [PATCH 228/388] Compute density in global ocean init mode --- .../mode_init/mpas_ocn_init_global_ocean.F | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F index 4a505b5b2be..6dc4f6849fb 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F @@ -34,6 +34,7 @@ module ocn_init_global_ocean use ocn_constants use ocn_config use ocn_diagnostics_variables + use ocn_equation_of_state use ocn_init_cell_markers use ocn_init_vertical_grids use ocn_init_interpolation @@ -123,7 +124,7 @@ subroutine ocn_init_setup_global_ocean(domain, iErr)!{{{ real (kind=RKIND), dimension(:, :), pointer :: PH_PREV_3D, PH_PREV_ALT_CO2_3D real (kind=RKIND), dimension(:, :), pointer :: FESEDFLUX - integer, dimension(:), pointer :: maxLevelCell + integer, dimension(:), pointer :: minLevelCell, maxLevelCell real (kind=RKIND), dimension(:, :), pointer :: normalVelocity real (kind=RKIND), dimension(:, :, :), pointer :: ecosysTracers, activeTracers, debugTracers, & @@ -502,6 +503,33 @@ subroutine ocn_init_setup_global_ocean(domain, iErr)!{{{ call mpas_dmpar_finalize(domain % dminfo) end if + call mpas_log_write( 'Compute density') + block_ptr => domain % blocklist + do while(associated(block_ptr)) + + call mpas_pool_get_subpool(block_ptr % structs, 'mesh', meshPool) + call mpas_pool_get_subpool(block_ptr % structs, 'state', statePool) + call mpas_pool_get_dimension(meshPool, 'nCells', nCells) + call mpas_pool_get_array(meshPool, 'minLevelCell', minLevelCell) + + do iCell = 1, nCells + do iTracer = 1,size(tracersSurfaceValue,1) + tracersSurfaceValue(iTracer, iCell) = activeTracers(iTracer, minLevelCell(iCell), iCell) + enddo + end do + + call ocn_equation_of_state_density(statePool, meshPool, tracersSurfaceValue, & + nCells, 0, 'relative', density, iErr, & + timeLevelIn=1) + + if(iErr .ne. 0) then + call mpas_log_write( 'ocn_equation_of_state_density failed.', MPAS_LOG_CRIT) + return + end if + + block_ptr => block_ptr % next + end do + if (config_global_ocean_cull_inland_seas) then call mpas_log_write( 'Removing inland seas.') call ocn_init_setup_global_ocean_cull_inland_seas(domain, iErr) From 0569e25fdfc0dc5fb3f876d74b7840579ea1a377 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 8 Apr 2024 13:21:02 -0500 Subject: [PATCH 229/388] Don't set ssh from landIceDraft in global ocean init Instead, it will be read in from the topography file directly, meaning it can be updated (e.g. from ssh adjustment). --- .../mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F index 6dc4f6849fb..855d2fd441b 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F @@ -129,7 +129,7 @@ subroutine ocn_init_setup_global_ocean(domain, iErr)!{{{ real (kind=RKIND), dimension(:, :), pointer :: normalVelocity real (kind=RKIND), dimension(:, :, :), pointer :: ecosysTracers, activeTracers, debugTracers, & DMSTracers, MacroMoleculesTracers - integer, pointer :: nVertLevels, nCellsSolve, tracerIndex + integer, pointer :: nVertLevels, nCellsSolve, nCells, tracerIndex integer :: iCell, k, iTracer integer, dimension(3) :: indexField @@ -965,8 +965,7 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i real (kind=RKIND), dimension(:), pointer :: landIceDraft, & landIcePressure, & landIceFraction, & - landIceFloatingFraction, & - ssh + landIceFloatingFraction integer, pointer :: nCells integer, dimension(:), pointer :: maxLevelCell, landIceMask, landIceFloatingMask @@ -1008,7 +1007,6 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i call mpas_pool_get_array(landIceInitPool, 'landIcePressureObserved', landIcePressureObserved) call mpas_pool_get_array(landIceInitPool, 'landIceFracObserved', landIceFracObserved) call mpas_pool_get_array(landIceInitPool, 'landIceFloatingFracObserved', landIceFloatingFracObserved) - call mpas_pool_get_array(statePool, 'ssh', ssh, 1) call mpas_pool_get_array(forcingPool, 'landIceMask', landIceMask) call mpas_pool_get_array(forcingPool, 'landIceFloatingMask', landIceFloatingMask) call mpas_pool_get_array(forcingPool, 'landIceDraft', landIceDraft) @@ -1021,7 +1019,6 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i 'indicates that this field is missing in the initial condition file (e.g. ' // & 'because it is meant for an older E3SM version).', MPAS_LOG_CRIT) endif - ssh(:) = 0.0_RKIND landIceFraction(:) = 0.0_RKIND landIceDraft(:) = 0.0_RKIND landIcePressure(:) = 0.0_RKIND @@ -1039,7 +1036,6 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i end if landIceDraft(iCell) = landIceDraftObserved(iCell) - ssh(iCell) = landIceDraft(iCell) landIcePressure(iCell) = landIcePressureObserved(iCell) if (landIcePressure(iCell) > 0.0_RKIND) then modifyLandIcePressureMask(iCell) = 1 From 2389f6f404f3b517674db4f9db77159e19d8e8c1 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 14 Apr 2024 15:43:21 +0200 Subject: [PATCH 230/388] Rename modifyLandIcePressureMask to sshAdjustmentMask this is a more accurate description for how it is uses, since it can determine where we modify either ssh or landIcePressure, depending on the approach. --- components/mpas-ocean/src/Registry.xml | 4 ++-- .../mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F | 4 ++-- components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip.F | 4 ++-- .../mpas-ocean/src/mode_init/mpas_ocn_init_isomip_plus.F | 6 +++--- .../src/mode_init/mpas_ocn_init_ssh_and_landIcePressure.F | 2 +- .../src/mode_init/mpas_ocn_init_sub_ice_shelf_2D.F | 4 ++-- .../mpas-ocean/src/shared/mpas_ocn_diagnostics_variables.F | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/mpas-ocean/src/Registry.xml b/components/mpas-ocean/src/Registry.xml index 7eb4f528dbf..825fe607a5b 100644 --- a/components/mpas-ocean/src/Registry.xml +++ b/components/mpas-ocean/src/Registry.xml @@ -2934,8 +2934,8 @@ - 0.0_RKIND) then - modifyLandIcePressureMask(iCell) = 1 + sshAdjustmentMask(iCell) = 1 end if end do diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip.F index 5299d36abb5..11874ea35d1 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip.F @@ -274,7 +274,7 @@ subroutine ocn_init_setup_isomip(domain, iErr)!{{{ landIceFraction(:) = 0.0_RKIND landIceSurfaceTemperature(:) = -25.0_RKIND !doesn't matter because ice is insulating - modifyLandIcePressureMask(:) = 0 + sshAdjustmentMask(:) = 0 landIceMask(:) = 0 @@ -301,7 +301,7 @@ subroutine ocn_init_setup_isomip(domain, iErr)!{{{ end if if(ssh(iCell) < 0.0_RKIND) then - modifyLandIcePressureMask(iCell) = 1 + sshAdjustmentMask(iCell) = 1 end if if(.not. associated(activeTracers)) then diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip_plus.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip_plus.F index e38d546762f..78436a13af4 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip_plus.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_isomip_plus.F @@ -529,9 +529,9 @@ subroutine ocn_init_setup_isomip_plus_interpolate_topo(domain, iErr)!{{{ do iCell = 1,nCells if(landIceFraction(iCell) > 0.01_RKIND) then - modifyLandIcePressureMask(iCell) = 1 + sshAdjustmentMask(iCell) = 1 else - modifyLandIcePressureMask(iCell) = 0 + sshAdjustmentMask(iCell) = 0 end if end do @@ -605,7 +605,7 @@ subroutine ocn_init_setup_isomip_plus_interpolate_topo(domain, iErr)!{{{ ssh(iCell) = 0.0_RKIND landIceFraction(iCell) = 0.0_RKIND landIceMask(iCell) = 0 - modifyLandIcePressureMask(iCell) = 0 + sshAdjustmentMask(iCell) = 0 end if end do !iCell diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_ssh_and_landIcePressure.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_ssh_and_landIcePressure.F index c85249635a7..e48f8982b6d 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_ssh_and_landIcePressure.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_ssh_and_landIcePressure.F @@ -159,7 +159,7 @@ subroutine ocn_init_ssh_and_landIcePressure_balance(domain, iErr)!{{{ end if do iCell = 1, nCells - if(modifyLandIcePressureMask(iCell) == 0) then + if(sshAdjustmentMask(iCell) == 0) then ssh(iCell) = 0.0_RKIND landIcePressure(iCell) = 0.0_RKIND diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_sub_ice_shelf_2D.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_sub_ice_shelf_2D.F index 6261b49e4b9..81c84e43e6b 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_sub_ice_shelf_2D.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_sub_ice_shelf_2D.F @@ -223,7 +223,7 @@ subroutine ocn_init_setup_sub_ice_shelf_2D(domain, iErr)!{{{ if(associated(landIceFraction)) & landIceFraction(:) = 0.0_RKIND - modifyLandIcePressureMask(:) = 0 + sshAdjustmentMask(:) = 0 if(associated(landIceMask)) & landIceMask(:) = 0 @@ -241,7 +241,7 @@ subroutine ocn_init_setup_sub_ice_shelf_2D(domain, iErr)!{{{ ssh(iCell) = -config_sub_ice_shelf_2D_bottom_depth + totalSubIceThickness if(ssh(iCell) < 0.0_RKIND) then - modifyLandIcePressureMask(iCell) = 1 + sshAdjustmentMask(iCell) = 1 end if end do diff --git a/components/mpas-ocean/src/shared/mpas_ocn_diagnostics_variables.F b/components/mpas-ocean/src/shared/mpas_ocn_diagnostics_variables.F index 00744a46737..be7eef2d806 100644 --- a/components/mpas-ocean/src/shared/mpas_ocn_diagnostics_variables.F +++ b/components/mpas-ocean/src/shared/mpas_ocn_diagnostics_variables.F @@ -127,7 +127,7 @@ module ocn_diagnostics_variables integer, dimension(:), pointer :: smoothingMask real (kind=RKIND), dimension(:,:), pointer :: verticalStretch - integer, dimension(:), pointer :: modifyLandIcePressureMask + integer, dimension(:), pointer :: sshAdjustmentMask real (kind=RKIND), dimension(:,:), pointer :: velocityMeridional real (kind=RKIND), dimension(:,:), pointer :: velocityZonal @@ -697,8 +697,8 @@ subroutine ocn_diagnostics_variables_init(domain, jenkinsOn, hollandJenkinsOn, e call mpas_pool_get_field(diagnosticsPool, 'verticalStretch', & verticalStretchField, 1) call mpas_pool_get_array(diagnosticsPool, & - 'modifyLandIcePressureMask', & - modifyLandIcePressureMask) + 'sshAdjustmentMask', & + sshAdjustmentMask) call mpas_pool_get_array(diagnosticsPool, 'indMLD', indMLD) call mpas_pool_get_array(diagnosticsPool, 'dThreshMLD', dThreshMLD) call mpas_pool_get_array(diagnosticsPool, 'surfacePressure', & From e0c0c0755b4e2e890876b1e8bf406cfc86b967a0 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 10 Jun 2024 08:51:30 -0500 Subject: [PATCH 231/388] Leave the landIce(Floating)Fraction unmasked This could allow us to choose to have melting bleed into cells that are partly open ocean (e.g. for conservation when coupling to MALI). --- .../src/mode_init/mpas_ocn_init_global_ocean.F | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F index 4a6b15285e0..692a19b7c64 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_global_ocean.F @@ -1027,13 +1027,10 @@ subroutine ocn_init_setup_global_ocean_interpolate_land_ice_topography(domain, i ! nothing to do here if the cell is land if (maxLevelCell(iCell) <= 0) cycle - if (landIceMask(iCell) == 1) then - landIceFraction(iCell) = landIceFracObserved(iCell) - end if - - if (landIceFloatingMask(iCell) == 1) then - landIceFloatingFraction(iCell) = landIceFloatingFracObserved(iCell) - end if + ! don't mask these because we may want to include melt that bleeds + ! into the open ocean + landIceFraction(iCell) = landIceFracObserved(iCell) + landIceFloatingFraction(iCell) = landIceFloatingFracObserved(iCell) landIceDraft(iCell) = landIceDraftObserved(iCell) landIcePressure(iCell) = landIcePressureObserved(iCell) From 2bd7c2af49666895bef1cb804ea54d30c5c02c47 Mon Sep 17 00:00:00 2001 From: Nicole Jeffery Date: Mon, 10 Jun 2024 13:55:01 -0500 Subject: [PATCH 232/388] Fix to using zaerosols without bgc -Shortened registry description for ocean bgc concentrations -Corrected some unit descriptions -Clean-up in mpas_seaice_icepack bugfix (BFB without bgc/zaerosols) --- components/mpas-seaice/driver/ice_comp_mct.F | 150 ++++++++++-------- components/mpas-seaice/src/Registry.xml | 16 +- components/mpas-seaice/src/icepack | 2 +- .../src/shared/mpas_seaice_constants.F | 2 +- .../src/shared/mpas_seaice_icepack.F | 113 +++---------- .../src/shared/mpas_seaice_initialize.F | 8 +- 6 files changed, 117 insertions(+), 174 deletions(-) diff --git a/components/mpas-seaice/driver/ice_comp_mct.F b/components/mpas-seaice/driver/ice_comp_mct.F index 50bf12ece37..3c579aee77a 100644 --- a/components/mpas-seaice/driver/ice_comp_mct.F +++ b/components/mpas-seaice/driver/ice_comp_mct.F @@ -2116,7 +2116,6 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_subpool(block_ptr % structs, 'biogeochemistry', biogeochemistry) if (config_use_zaerosols) then - call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) call mpas_pool_get_array(biogeochemistry, 'atmosBlackCarbonFlux', atmosBlackCarbonFlux) call mpas_pool_get_array(biogeochemistry, 'atmosDustFlux', atmosDustFlux) call mpas_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) @@ -2232,13 +2231,16 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ endif ! set aerosols, if configured - if (config_use_zaerosols) then + if (config_use_zaerosols .or. config_use_column_biogeochemistry) then + call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) oceanZAerosolConc(1,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer1, n) oceanZAerosolConc(2,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer2, n) oceanZAerosolConc(3,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer3, n) oceanZAerosolConc(4,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer4, n) oceanZAerosolConc(5,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer5, n) oceanZAerosolConc(6,i) = 0.0_RKIND !x2i_i % rAttr(index_x2i_So_zaer6, n) + end if + if (config_use_zaerosols) then if (config_use_modal_aerosols) then atmosBlackCarbonFlux(1,i) = x2i_i % rAttr(index_x2i_Faxa_bcphodry, n) & + x2i_i % rAttr(index_x2i_Faxa_bcphidry, n) @@ -2370,12 +2372,14 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ call mpas_pool_get_field(aerosols, "atmosAerosolFlux", atmosAerosolFluxField) endif + if (config_use_zaerosols .or. config_use_column_biogeochemistry) & + call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) + if (config_use_zaerosols) then call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) call mpas_pool_get_field(biogeochemistry, "atmosWetDustFlux", atmosWetDustFluxField) call mpas_pool_get_field(biogeochemistry, "atmosDryDustFlux", atmosDryDustFluxField) - call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) endif if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then call mpas_pool_get_subpool(domain % blocklist % structs, 'biogeochemistry', biogeochemistry) @@ -2422,12 +2426,14 @@ subroutine ice_import_mct(x2i_i, errorCode)!{{{ if (config_use_aerosols) then call mpas_dmpar_exch_halo_field(atmosAerosolFluxField) endif + if (config_use_zaerosols .or. config_use_column_biogeochemistry) & + call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) + if (config_use_zaerosols) then call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) call mpas_dmpar_exch_halo_field(atmosDustFluxField) call mpas_dmpar_exch_halo_field(atmosDryDustFluxField) call mpas_dmpar_exch_halo_field(atmosWetDustFluxField) - call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) endif if (config_use_column_biogeochemistry .and. config_couple_biogeochemistry_fields) then call mpas_dmpar_exch_halo_field(oceanAlgaeConcField) @@ -3752,9 +3758,7 @@ subroutine ice_import_moab(Eclock)!{{{ endif if (config_use_column_biogeochemistry) then - call mpas_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) call mpas_pool_get_subpool(block_ptr % structs, 'biogeochemistry', biogeochemistry) - call mpas_pool_get_array(biogeochemistry, 'oceanAlgaeConc', oceanAlgaeConc) call mpas_pool_get_array(biogeochemistry, 'oceanDOCConc', oceanDOCConc) call mpas_pool_get_array(biogeochemistry, 'oceanDICConc', oceanDICConc) @@ -3767,16 +3771,19 @@ subroutine ice_import_moab(Eclock)!{{{ call mpas_pool_get_array(biogeochemistry, 'oceanHumicsConc', oceanHumicsConc) call mpas_pool_get_array(biogeochemistry, 'oceanParticulateIronConc', oceanParticulateIronConc) call mpas_pool_get_array(biogeochemistry, 'oceanDissolvedIronConc', oceanDissolvedIronConc) - call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioAlgae', carbonToNitrogenRatioAlgae) call mpas_pool_get_array(biogeochemistry, 'carbonToNitrogenRatioDON', carbonToNitrogenRatioDON) + endif + + call mpas_pool_get_config(configs, "config_use_zaerosols", config_use_zaerosols) if (config_use_zaerosols) then call mpas_pool_get_array(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFlux) call mpas_pool_get_array(biogeochemistry, "atmosDustFlux", atmosDustFlux) call mpas_pool_get_array(biogeochemistry, "atmosWetDustFlux", atmosWetDustFlux) call mpas_pool_get_array(biogeochemistry, "atmosDryDustFlux", atmosDryDustFlux) endif - endif + if (config_use_column_biogeochemistry .or. config_use_zaerosols) & + call mpas_pool_get_array(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConc) do i = 1, nCellsSolve n = n + 1 @@ -3883,65 +3890,67 @@ subroutine ice_import_moab(Eclock)!{{{ oceanParticulateIronConc(2,i) = x2i_im(n,index_x2i_So_fep2) oceanDissolvedIronConc(1,i) = x2i_im(n,index_x2i_So_fed1) oceanDissolvedIronConc(2,i) = x2i_im(n,index_x2i_So_fed2) + endif + if (config_use_zaerosols .or. config_use_column_biogeochemistry) then oceanZAerosolConc(1,i) = 0.0_RKIND oceanZAerosolConc(2,i) = 0.0_RKIND oceanZAerosolConc(3,i) = 0.0_RKIND oceanZAerosolConc(4,i) = 0.0_RKIND oceanZAerosolConc(5,i) = 0.0_RKIND oceanZAerosolConc(6,i) = 0.0_RKIND - ! set aerosols, if configured - if (config_use_zaerosols) then - if (config_use_modal_aerosols) then - atmosBlackCarbonFlux(1,i) = x2i_im(n,index_x2i_Faxa_bcphodry) & - + x2i_im(n,index_x2i_Faxa_bcphidry) - atmosBlackCarbonFlux(2,i) = x2i_im(n,index_x2i_Faxa_bcphiwet) - ! combine wet and dry dust - atmosDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) & - + x2i_im(n,index_x2i_Faxa_dstdry1) - atmosDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) & - + x2i_im(n,index_x2i_Faxa_dstdry2) - atmosDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) & - + x2i_im(n,index_x2i_Faxa_dstdry3) - atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & - + x2i_im(n,index_x2i_Faxa_dstdry4) - - ! wet dust - atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) - atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) - atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) - atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) - - ! dry dust - atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) - atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) - atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) - atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) - else - atmosBlackCarbonFlux(1,i) = x2i_im(n,index_x2i_Faxa_bcphodry) - atmosBlackCarbonFlux(2,i) = x2i_im(n,index_x2i_Faxa_bcphidry) & - + x2i_im(n,index_x2i_Faxa_bcphiwet) - ! combine wet and dry dust - atmosDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) & - + x2i_im(n,index_x2i_Faxa_dstdry1) - atmosDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) & - + x2i_im(n,index_x2i_Faxa_dstdry2) - atmosDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) & - + x2i_im(n,index_x2i_Faxa_dstdry3) - atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & - + x2i_im(n,index_x2i_Faxa_dstdry4) - - ! wet dust - atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) - atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) - atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) - atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) - - ! dry dust - atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) - atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) - atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) - atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) - endif + end if + ! set zaerosols, if configured + if (config_use_zaerosols) then + if (config_use_modal_aerosols) then + atmosBlackCarbonFlux(1,i) = x2i_im(n,index_x2i_Faxa_bcphodry) & + + x2i_im(n,index_x2i_Faxa_bcphidry) + atmosBlackCarbonFlux(2,i) = x2i_im(n,index_x2i_Faxa_bcphiwet) + ! combine wet and dry dust + atmosDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) & + + x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) & + + x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) & + + x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & + + x2i_im(n,index_x2i_Faxa_dstdry4) + + ! wet dust + atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) + atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) + atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) + atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) + + ! dry dust + atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) + else + atmosBlackCarbonFlux(1,i) = x2i_im(n,index_x2i_Faxa_bcphodry) + atmosBlackCarbonFlux(2,i) = x2i_im(n,index_x2i_Faxa_bcphidry) & + + x2i_im(n,index_x2i_Faxa_bcphiwet) + ! combine wet and dry dust + atmosDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) & + + x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) & + + x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) & + + x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) & + + x2i_im(n,index_x2i_Faxa_dstdry4) + + ! wet dust + atmosWetDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstwet1) + atmosWetDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstwet2) + atmosWetDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstwet3) + atmosWetDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstwet4) + + ! dry dust + atmosDryDustFlux(1,i) = x2i_im(n,index_x2i_Faxa_dstdry1) + atmosDryDustFlux(2,i) = x2i_im(n,index_x2i_Faxa_dstdry2) + atmosDryDustFlux(3,i) = x2i_im(n,index_x2i_Faxa_dstdry3) + atmosDryDustFlux(4,i) = x2i_im(n,index_x2i_Faxa_dstdry4) endif endif end do @@ -4020,15 +4029,15 @@ subroutine ice_import_moab(Eclock)!{{{ call mpas_pool_get_field(biogeochemistry, 'oceanHumicsConc', oceanHumicsConcField) call mpas_pool_get_field(biogeochemistry, 'oceanParticulateIronConc', oceanParticulateIronConcField) call mpas_pool_get_field(biogeochemistry, 'oceanDissolvedIronConc', oceanDissolvedIronConcField) + endif + if (config_use_zaerosols .or. config_use_column_biogeochemistry) & call mpas_pool_get_field(biogeochemistry, 'oceanZAerosolConc', oceanZAerosolConcField) - if (config_use_zaerosols) then - call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) - call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) - call mpas_pool_get_field(biogeochemistry, "atmosWetDustFlux", atmosWetDustFluxField) - call mpas_pool_get_field(biogeochemistry, "atmosDryDustFlux", atmosDryDustFluxField) - endif + if (config_use_zaerosols) then + call mpas_pool_get_field(biogeochemistry, "atmosBlackCarbonFlux", atmosBlackCarbonFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosDustFlux", atmosDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosWetDustFlux", atmosWetDustFluxField) + call mpas_pool_get_field(biogeochemistry, "atmosDryDustFlux", atmosDryDustFluxField) endif - call mpas_dmpar_exch_halo_field(seaSurfaceTemperatureField) call mpas_dmpar_exch_halo_field(seaSurfaceSalinityField) call mpas_dmpar_exch_halo_field(seaFreezingTemperatureField) @@ -4071,13 +4080,14 @@ subroutine ice_import_moab(Eclock)!{{{ call mpas_dmpar_exch_halo_field(oceanHumicsConcField) call mpas_dmpar_exch_halo_field(oceanParticulateIronConcField) call mpas_dmpar_exch_halo_field(oceanDissolvedIronConcField) + endif + if (config_use_zaerosols .or. config_use_column_biogeochemistry) & call mpas_dmpar_exch_halo_field(oceanZAerosolConcField) - if (config_use_zaerosols) then + if (config_use_zaerosols) then call mpas_dmpar_exch_halo_field(atmosBlackCarbonFluxField) call mpas_dmpar_exch_halo_field(atmosDustFluxField) call mpas_dmpar_exch_halo_field(atmosWetDustFluxField) call mpas_dmpar_exch_halo_field(atmosDryDustFluxField) - endif endif ! REVISION HISTORY: diff --git a/components/mpas-seaice/src/Registry.xml b/components/mpas-seaice/src/Registry.xml index b4ffd634bd2..22c11fe28f2 100644 --- a/components/mpas-seaice/src/Registry.xml +++ b/components/mpas-seaice/src/Registry.xml @@ -5402,7 +5402,7 @@ type="real" dimensions="nZBGCTracers nCells Time" units="mmol m-3" - description="All bio tracers including those not used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m3, particulate iron in umol/m3, humic carbon, black carbon1 in mg/m3, black carbon2 in mg/m3,dust1 in mg/m3, dust2 in mg/m3, dust3 in mg/m3, dust4 in mg/m3" + description="All possible bio tracers in order: maxAlgaeType, nitrate, maxDOCType, maxDICType, chl (maxAlgaeType), ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, maxDONType, dFe (maxFeType, umol/m3), pFe (maxFeType, umol/m3), maxBCType (kg/m3), maxDustType (kg/m3), humic carbon" icepack_name="ocean_bio" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> @@ -5410,7 +5410,7 @@ type="real" dimensions="nZBGCTracers nCells Time" units="mmol m-3" - description="Only bio tracers used in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon,dissolved inorganic carbon, ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m3, particulate iron in umol/m3, humic carbon, black carbon1 in mg/m3, black carbon2 in mg/m3,dust1 in mg/m3, dust2 in mg/m3, dust3 in mg/m3, dust4 in mg/m3" + description="Bio tracers used in the order of oceanBioConcentrations" icepack_name="ocean_bio" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> @@ -5418,7 +5418,7 @@ type="real" dimensions="nZBGCTracers nCells Time" units="mmol m-2" - description="Only bio tracers used and added to sea ice bottom in the order: diatom nitrogen, smallPlankton nitrogen, phaeocystis nitrogen, nitrate, polysaccarid carbon, lipid carbon, dissolved inorganic carbon,ammonium, silicate, DMSPp, DMSPd, DMS, Nonreactive nitrate, Protein nitrogen, dissolved iron in umol/m2, particulate iron in umol/m2, humic carbon, black carbon1 in mg/m2, black carbon2 in mg/m2,dust1 in mg/m2, dust2 in mg/m2, dust3 in mg/m2, dust4 in mg/m2" + description="Bio tracers used and added to sea ice bottom in the order of oceanBioConcentrations" icepack_name="ocean_bio" packages="pkgColumnBiogeochemistry;pkgColumnPackage" /> @@ -5498,7 +5498,7 @@ Date: Mon, 10 Jun 2024 16:04:32 -0500 Subject: [PATCH 233/388] update Makefile for cube_to_target --- .../tools/topo_tool/cube_to_target/Makefile | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/components/eam/tools/topo_tool/cube_to_target/Makefile b/components/eam/tools/topo_tool/cube_to_target/Makefile index 5a1f386b819..98ace1a4f5b 100644 --- a/components/eam/tools/topo_tool/cube_to_target/Makefile +++ b/components/eam/tools/topo_tool/cube_to_target/Makefile @@ -24,35 +24,14 @@ endif # Set default compile and link flags FFLAGS = -L$(LIB_NETCDF) -I$(INC_NETCDF) -#LDFLAGS = -L$(LIB_NETCDF) -lnetcdf -lnetcdff -lcurl -lhdf5 -lhdf5_hl -mcmodel=medium -LDFLAGS = -L$(LIB_NETCDF) -lnetcdf -lnetcdff -lcurl +LDFLAGS = -L$(LIB_NETCDF) -lnetcdf -lnetcdff # Determine platform UNAMES := $(shell uname -s) UNAMEM := $(findstring CRAY,$(shell uname -m)) #------------------------------------------------------------------------ -# Special flags for LF95 #------------------------------------------------------------------------ -# -ifeq ($(FC),lf95) - # - # Tramhill - # - INC_NETCDF :=/usr/local/netcdf-4.1.3-gcc-4.4.4-13-lf9581/include - LIB_NETCDF :=/usr/local/netcdf-4.1.3-gcc-4.4.4-13-lf9581/lib - - LDFLAGS = -L$(LIB_NETCDF) -lnetcdf -lnetcdff -lcurl -lhdf5 -lhdf5_hl --mcmodel=medium - FFLAGS := -c --trace --trap --wide -CcdRR8 -I$(INC_NETCDF) - ifeq ($(DEBUG),TRUE) - #FFLAGS += --chk aesu -Cpp --trace - FFLAGS += -g --chk a,e,s,u --pca - else - FFLAGS += -O - endif - -endif .F90.o: $(FC) -c $(FFLAGS) $< From 266c9d69ff56603c4b59ec88ab5c5168f0074bd5 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 11 Jun 2024 09:17:34 -0500 Subject: [PATCH 234/388] Use sshAdjustmentMask instead of landIceMask for rx1 smoothing mask This is needed because otherwise locations with nonzero ice draft get missed and the Haney number may be too high for model stability. --- .../src/mode_init/mpas_ocn_init_vertical_grids.F | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/mpas-ocean/src/mode_init/mpas_ocn_init_vertical_grids.F b/components/mpas-ocean/src/mode_init/mpas_ocn_init_vertical_grids.F index 2fcbf507f7a..bc535ec865f 100644 --- a/components/mpas-ocean/src/mode_init/mpas_ocn_init_vertical_grids.F +++ b/components/mpas-ocean/src/mode_init/mpas_ocn_init_vertical_grids.F @@ -1079,7 +1079,7 @@ subroutine ocn_init_vertical_grid_with_max_rx1(domain, iErr) type (block_type), pointer :: block_ptr - type (mpas_pool_type), pointer :: meshPool, statePool, verticalMeshPool, scratchPool, forcingPool + type (mpas_pool_type), pointer :: meshPool, statePool, verticalMeshPool, scratchPool, diagnosticsPool integer, pointer :: config_rx1_outer_iter_count, config_rx1_inner_iter_count, & config_rx1_horiz_smooth_open_ocean_cells, config_rx1_min_levels @@ -1095,7 +1095,7 @@ subroutine ocn_init_vertical_grid_with_max_rx1(domain, iErr) real (kind=RKIND), dimension(:,:), pointer :: layerThickness, restingThickness, zInterface, & goalStretch, goalWeight - integer, dimension(:), pointer :: landIceMask + integer, dimension(:), pointer :: sshAdjustmentMask real (kind=RKIND), dimension(:), pointer :: ssh, bottomDepth, refBottomDepth, zTop, zBot, zBotNew, & refLayerThickness @@ -1142,14 +1142,14 @@ subroutine ocn_init_vertical_grid_with_max_rx1(domain, iErr) block_ptr => domain % blocklist do while(associated(block_ptr)) call mpas_pool_get_subpool(block_ptr % structs, 'mesh', meshPool) - call mpas_pool_get_subpool(block_ptr % structs, 'forcing', forcingPool) + call mpas_pool_get_subpool(block_ptr % structs, 'diagnostics', diagnosticsPool) call mpas_pool_get_dimension(meshPool, 'nCells', nCells) call mpas_pool_get_array(meshPool, 'cullCell', cullCell) call mpas_pool_get_array(meshPool, 'maxLevelCell', maxLevelCell) - call mpas_pool_get_array(forcingPool, 'landIceMask', landIceMask) + call mpas_pool_get_array(diagnosticsPool, 'sshAdjustmentMask', sshAdjustmentMask) maxLevelCell(nCells+1) = -1 do iCell = 1, nCells @@ -1163,7 +1163,7 @@ subroutine ocn_init_vertical_grid_with_max_rx1(domain, iErr) ! initialize the smoothing mask to valid cells under land ice smoothingMask(:) = 0 - where((maxLevelCell(:) > 0) .and. (landIceMask(:) == 1)) + where((maxLevelCell(:) > 0) .and. (sshAdjustmentMask(:) == 1)) smoothingMask(:) = 1 end where From cdadd6f8d0ae827b29f7f5e094c7ef94ec44af4f Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 11 Jun 2024 08:10:30 -0700 Subject: [PATCH 235/388] update fates tag to sci.1.76.4_api.35.1.0 --- components/elm/src/external_models/fates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/src/external_models/fates b/components/elm/src/external_models/fates index f0185f7c703..b8e4eee5ed4 160000 --- a/components/elm/src/external_models/fates +++ b/components/elm/src/external_models/fates @@ -1 +1 @@ -Subproject commit f0185f7c7033fa69c80d1ddb07cbcbf1f8be1adc +Subproject commit b8e4eee5ed46daf5c9e710e9ebbe6d20464adbc8 From 47746069761e12fee44c6cfff72c65594ae4a4a4 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 11 Jun 2024 13:30:49 -0700 Subject: [PATCH 236/388] update variable intent --- .../eam/tools/topo_tool/cube_to_target/cube_to_target.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/tools/topo_tool/cube_to_target/cube_to_target.F90 b/components/eam/tools/topo_tool/cube_to_target/cube_to_target.F90 index 97d23fa8476..850815efdbf 100644 --- a/components/eam/tools/topo_tool/cube_to_target/cube_to_target.F90 +++ b/components/eam/tools/topo_tool/cube_to_target/cube_to_target.F90 @@ -1576,7 +1576,7 @@ SUBROUTINE overlap_weights(weights_lgr_index_all,weights_eul_index_all,weights_a REAL(R8), DIMENSION(jall,nreconstruction) , INTENT(OUT) :: weights_all INTEGER, DIMENSION(jall) , INTENT(OUT) :: weights_lgr_index_all - REAL(R8), DIMENSION(ncorner,ntarget), INTENT(IN) :: target_corner_lon, target_corner_lat + REAL(R8), DIMENSION(ncorner,ntarget), INTENT(INOUT) :: target_corner_lon, target_corner_lat INTEGER, DIMENSION(ncorner+1) :: ipanel_array, ipanel_tmp REAL(R8), DIMENSION(ncorner) :: lat, lon From 7c2557dd47640b5b7c6d42ce7f48fcbe220f66a7 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 11 Jun 2024 14:28:13 -0700 Subject: [PATCH 237/388] simplify Makefile some more --- .../tools/topo_tool/cube_to_target/Makefile | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/components/eam/tools/topo_tool/cube_to_target/Makefile b/components/eam/tools/topo_tool/cube_to_target/Makefile index 98ace1a4f5b..72ffd73c2a4 100644 --- a/components/eam/tools/topo_tool/cube_to_target/Makefile +++ b/components/eam/tools/topo_tool/cube_to_target/Makefile @@ -5,26 +5,20 @@ RM = rm .SUFFIXES: .SUFFIXES: .F90 .o -# Set the compiler; note that on some platforms, FC may be defined as an -# environment variable, and we should not need to do anything here. If this -# is the case, skip setting FC, but if FC is null then set to a default. -ifeq ($(FC),$(null)) - FC = gfortran -endif -DEBUG = FALSE - -# Check for the NetCDF library and include directories -ifeq ($(LIB_NETCDF),$(null)) - LIB_NETCDF := /usr/local/lib -endif +# Set the compiler +FC := gfortran -ifeq ($(INC_NETCDF),$(null)) - INC_NETCDF := /usr/local/include -endif +# Set NetCDF library and include directories +LIB_NETCDF := $(shell nf-config --prefix)/lib +INC_NETCDF := $(shell nf-config --prefix)/include # Set default compile and link flags -FFLAGS = -L$(LIB_NETCDF) -I$(INC_NETCDF) -LDFLAGS = -L$(LIB_NETCDF) -lnetcdf -lnetcdff +FFLAGS += -L$(LIB_NETCDF) -I$(INC_NETCDF) +LDFLAGS += -L$(LIB_NETCDF) -lnetcdf -lnetcdff + +ifeq ($(FC),gfortran) + FFLAGS += -fallow-argument-mismatch +endif # Determine platform UNAMES := $(shell uname -s) From ae0ed99e930408346b135cd1aabcbc408cc49cc5 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 12 Jun 2024 08:54:47 -0600 Subject: [PATCH 238/388] major overhaul of topo workflow --- .../generate-topo-file.md | 782 ++++++++++++------ 1 file changed, 533 insertions(+), 249 deletions(-) diff --git a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md index 42cc7b9a089..91233cecdac 100644 --- a/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md +++ b/docs/dev-guide/adding-grid-support/adding-grid-support-step-by-step-guide/generate-topo-file.md @@ -1,16 +1,18 @@ + + + + # Generate a Topography File -Topography needs to be interpolated from a high resolution USGS file, and then doctored up a bit to allow the model to run stably with the new topography. The tool chain used to compute topography is documented in the following paper: +Topography needs to be interpolated from a high resolution dataset, and then doctored a bit to allow the model to run stably with the new topography. More information can be found in the following paper: [P.H. Lauritzen, J.T. Bacmeister, P.F. Callaghan, M. Taylor, NCAR_Topo (v1.0): NCAR global model topography generation software for unstructured grids, Geosci. Model Dev., 8, 3975-3986, 2015.](https://www.geosci-model-dev.net/8/3975/2015/) -## Input Topography Data +Typically, input topography data generation for E3SM starts with a high resolution source dataset (`USGS-topo-cube3000.nc`). This is a high-resolution topography dataset on a 3km cubed sphere grid derived from 1 km resolution source data. This file is located in the [CESM inputdata server here](https://svn-ccsm-inputdata.cgd.ucar.edu/trunk/inputdata/atm/cam/hrtopo/). -Traditionally the topography generation for E3SM start with **USGS-topo-cube3000.nc**, which is included in the [E3SM inputdata repository]. This is a high-resolution topography dataset on a 3km cubed sphere grid derived from 1 km resolution source data. This file is located in the [CESM inputdata server here](https://svn-ccsm-inputdata.cgd.ucar.edu/trunk/inputdata/atm/cam/hrtopo/). +For target resolutions of 3 km or finer it is recommended to use an even higher resolution source dataset (`USGS-topo-cube12000.nc`), which was created by Jishi Zhang in 2024. This file has a resolution of 750m created from a 500m/250m USGS GMTED2010 source DEM dataset (see [here](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/4189520033/800m+cubed+topo+generation+from+GMTED2010+15s+DEM) for more information). -For target resolutions of 3 km or finer it is recommended to use **USGS-topo-cube12000.nc**, which was created by Jishi Zhang in 2024. This file has a resolution of 750m created from a 500m/250m USGS GMTED2010 source DEM dataset (see [here](https://acme-climate.atlassian.net/wiki/spaces/DOC/pages/4189520033/800m+cubed+topo+generation+from+GMTED2010+15s+DEM) for more information). - -For testing the topography workflow the mapping between the ne3000 data is much too burdensome, so a ne90pg1 (i.e. 1-degree) version of this data was created to allow efficient testing. This file can be found in the inputdata repository at `${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube90.nc`. +For testing the topography workflow the mapping between the ne3000 data is too burdensome, so a ne90pg1 (i.e. 1-degree) version of this data was created to allow efficient testing. This file can be found on various supported machines at `${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube90.nc`. ## Data Processing Requirements @@ -28,343 +30,393 @@ The workflow to generate topography data for the atmosphere model must address t Smoothing of the input surface geopotential (`phi_s`) is an essential step to ensure numerical stability of the atmospheric dynamics, but the smoothing much be done in a way that is consistent with the internal Laplacian used by the HOMME dycor. To accomplish this we use `homme_tool`, which is a standalone build of the HOMME dycor. +### Building homme_tool + !!! NOTE homme_tool is not routinely tested on all supported machines, and the build can be broken without anyone noticing. If you encounter problems building homme_tool please reach out on the e3sm_help slack channel and include a detailed description of the error and the commands you used to produce the error. - - - +Building `homme_tool` is a critical preliminary step to the topography generation workflow described below. The build process requires the user to select the appropriate cmake file that contains machine-specific settings (see `mach_file` below). + +```shell +# Set the machine specific environment +cd ${e3sm_root}/components/homme +${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh + +# Specify machine configuration file +mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake +# mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake + +cmake -C ${mach_file} \ +-DBUILD_HOMME_THETA_KOKKOS=FALSE \ +-DBUILD_HOMME_PREQX_KOKKOS=FALSE \ +-DHOMME_ENABLE_COMPOSE=FALSE \ +-DHOMME_BUILD_EXECS=FALSE \ +-DBUILD_HOMME_TOOL=TRUE \ +-DBUILD_HOMME_WITHOUT_PIOLIBRARY=FALSE \ +-DPREQX_PLEV=26 \ +${e3sm_root}/components/homme + +make -j4 homme_tool +``` + +## Sub-Grid Topography Variations + +Certain physics calculations in the atmosphere require a characterization of the unresolved topography. This is provided in the input data as `SGH` and `SGH30`. These quantities need to be calculated by the `cube_to_target` tool that is included in the E3SM source code. Similar to `homme_tool`, this tool can often be broken when the user goes to use it. Luckily, this tool is much simpler with fewer dependencies. Nevertheless, it is good to make sure the tools builds successfully before creating a new topography file. + +### Building cube_to_target + +The following commands were working on both Perlmutter/NERSC and Chrysalis/LCRC machines as of 2024. + +```shell +cd ${e3sm_root}/components/eam/tools/topo_tool/cube_to_target + +${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh + +make +``` + +!!! NOTE + You can safely ignore compiler warnings that look like this: + + `Warning: Rank mismatch between actual argument at (1) and actual argument at (2) (scalar and rank-1)` + + These are a result of how we interface with the netcdf fortran routines, but fixing the warnings by switching from `#include ` to `use netcdf` can lead to other problems on certain machines. ## Step-by-Step Topography Generation -1. **Set some helpful environmental variables used in commands below** +!!! NOTE + Copying and pasting the relevant steps below is an easy way to step through the blocks of commands. Alternatively, a batch script is provided below that can be used to execute all steps at once in a batch job. - ```shell - e3sm_root= - grid_root= - map_root= - topo_root= - DIN_LOC_ROOT= - NE_SRC= - NE_DST= - ``` +1. ### **Activate the E3SM Unified Env** - Example path settings for Perlmutter (NERSC): + Perlmutter (NERSC): ```shell - grid_root=${SCRATCH}/e3sm_scratch/files_grid - map_root=${SCRATCH}/e3sm_scratch/files_map - topo_root=${SCRATCH}/e3sm_scratch/files_topo - DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata + source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh ``` - Example path settings for Chrysalis (ANL/LCRC): + Chrysalis (ANL/LCRC): ```shell - grid_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_grid - map_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_map - topo_root=/lcrc/group/e3sm/${USER}/scratch/chrys/files_topo - DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata + source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh ``` - Make sure the directories exist: - +1. ### **Specify Source and Target Resolution** + + We will environement variables to specify the source and target grid resolutions based on the "ne" value of the cubed sphere grid ("ne" is the number of elements along a cube edge). A Typical use case will be mapping data from `ne3000pg1` to a chosen target resolution, in this case `ne30` : + ```shell - mkdir -p ${grid_root} ${map_root} ${topo_root} + NE_SRC=3000 + NE_DST=30 ``` -1. **Specify all topo and map file paths for consistency** + For testing use a special `ne90pg1` dataset: ```shell - # topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc - # topo_file_1=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4.nc - # topo_file_2=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_phis.nc - # topo_file_3=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t.nc - # topo_file_4=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1.nc - # topo_file_5=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1_anomalies.nc - # topo_file_6=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_anomalies.nc - # topo_file_7=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_sgh.nc - # topo_file_8=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothedx6t.nc + NE_SRC=90 + NE_DST=4 + ``` + !!! NOTE + For grids with regional refinement (RRM) there is no corresponding "ne" value - so a slightly modified workflow is needed. This entails modifying the grid file generation step, and then modifying topo and map file paths to accomodate the new RRM grid name. + (Hopefully we added a batch script above/below to provide an example of this modified workflow?) - topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc - topo_file_1=${topo_root}/USGS-topo_tmp_ne${NE_SRC}pg1.nc - topo_file_2=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4.nc - topo_file_3=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t.nc - topo_file_4=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1.nc - topo_file_5=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_ne${NE_SRC}pg1_anomalies.nc - topo_file_6=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_anomalies.nc - topo_file_7=${topo_root}/USGS-topo_tmp_ne${NE_DST}np4_smoothedx6t_sgh.nc - topo_file_8=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothedx6t.nc +1. ### **Specify File Paths** + + First we need to set some enviroment variables that point to various "root" directories where we will be writing and/or reading files. It - map_file_src_to_np4=${map_root}/map_ne${NE_SRC}pg1_to_ne${NE_DST}np4_fv2se_flx.nc - map_file_src_to_pg2=${map_root}/map_ne${NE_SRC}pg1_to_ne${NE_DST}pg2_traave.nc - map_file_pg2_to_src=${map_root}/map_ne${NE_DST}pg2_to_ne${NE_SRC}pg1_traave.nc - map_file_np4_to_pg2=${map_root}/map_ne${NE_DST}np4_to_ne${NE_DST}pg2_se2fv_flx.nc + ```shell + e3sm_root=? # path to E3SM source + grid_root=? # path to write grid files + map_root=? # path to write map files + topo_root=? # path to write new topo files + DIN_LOC_ROOT=? # path to E3SM inputdata ``` -1. **Create grid and map files** - - 1. source the unified env - - Perlmutter (NERSC): + Example path settings: + + - Perlmutter (NERSC): ```shell - source /global/common/software/e3sm/anaconda_envs/load_latest_e3sm_unified_pm-cpu.sh + e3sm_root=${SCRATCH}/tmp_e3sm_src # make sure this contains an up-to-date clone of E3SM + grid_root=${SCRATCH}/e3sm_scratch/files_grid + map_root=${SCRATCH}/e3sm_scratch/files_map + topo_root=${SCRATCH}/e3sm_scratch/files_topo + DIN_LOC_ROOT=/global/cfs/cdirs/e3sm/inputdata ``` - Chrysalis (ANL/LCRC): + - Chrysalis (ANL/LCRC): ```shell - source /lcrc/soft/climate/e3sm-unified/load_latest_e3sm_unified_chrysalis.sh + SCRATCH=/lcrc/group/e3sm/${USER}/scratch/chrys + e3sm_root=${SCRATCH}/tmp_e3sm_src # make sure this contains an up-to-date clone of E3SM + grid_root=${SCRATCH}/files_grid + map_root=${SCRATCH}/files_map + topo_root=${SCRATCH}/files_topo + DIN_LOC_ROOT=/lcrc/group/e3sm/data/inputdata ``` - 1. Create grid files - - ```shell - # Grid for source high res topo - GenerateCSMesh --alt --res ${NE_SRC} --file ${grid_root}/exodus_ne${NE_SRC}.g - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_SRC}.g --out ${grid_root}/scrip_ne${NE_SRC}pg1.nc - - # Grid for target EAM grid - GenerateCSMesh --alt --res ${NE_DST} --file ${grid_root}/exodus_ne${NE_DST}.g - GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE_DST}.g --out ${grid_root}/exodus_ne${NE_DST}pg2.g --np 2 --uniform - ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_DST}pg2.g --out ${grid_root}/scrip_ne${NE_DST}pg2.nc - ``` + Make sure the root directories exist: - 1. Create map files + ```shell + mkdir -p ${grid_root} ${map_root} ${topo_root} + ls -ld ${grid_root} ${map_root} ${topo_root} ${e3sm_root} ${DIN_LOC_ROOT} + ``` - !!!WARNING - This can take a long time - several hours for each map file in some cases + Now specify all the files that we will need for, including map files and temporary topo data. - ```shell - # from source to target np4 - ncremap -a fv2se_flx -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/exodus_ne${NE_DST}.g --map_file=${map_file_src_to_np4} - - # from source to target pg2 - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --dst_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --map_file=${map_file_src_to_pg2} - - # from target to source (needed for calculating sub-grid anomalies on target grid) - ncremap -a traave -5 --src_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --dst_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc --map_file=${ - map_file_pg2_to_src} + ```shell + timestamp=$(date +%Y%m%d) + topo_file_0=${DIN_LOC_ROOT}/atm/cam/hrtopo/USGS-topo-cube${NE_SRC}.nc + topo_file_1=${topo_root}/tmp_USGS-topo_ne${NE_DST}np4.nc + topo_file_2=${topo_root}/tmp_USGS-topo_ne${NE_DST}np4_smoothedx6t.nc + topo_file_3=${topo_root}/USGS-topo_ne${NE_DST}np4_smoothedx6t_${timestamp}.nc - # from target np4 to target pg2 - ncremap -a se2fv_flx -5 --src_grd=${grid_root}/exodus_ne${NE_DST}.g --dst_grd=${grid_root}/scrip_ne${NE_DST}pg2.nc --map_file=${map_file_np4_to_pg2} - ``` + map_file_src_to_np4=${map_root}/map_ne${NE_SRC}pg1_to_ne${NE_DST}np4_fv2se_flx.nc + ``` -1. **Create new topograpy data on target grid** +1. ### **Create Grid Files** ```shell - # # Map high-res topo to target np4 grid - # ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - - # # Compute phi_s on the np4 grid - # ncap2 -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_2} + # Grid for source high res topo + GenerateCSMesh --alt --res ${NE_SRC} --file ${grid_root}/exodus_ne${NE_SRC}.g + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_SRC}.g --out ${grid_root}/scrip_ne${NE_SRC}pg1.nc - # # rename the column dimension to be "ncol" - # ncrename -d grid_size,ncol ${topo_file_2} + # Grid for target EAM grid + GenerateCSMesh --alt --res ${NE_DST} --file ${grid_root}/exodus_ne${NE_DST}.g + GenerateVolumetricMesh --in ${grid_root}/exodus_ne${NE_DST}.g --out ${grid_root}/exodus_ne${NE_DST}pg2.g --np 2 --uniform + ConvertMeshToSCRIP --in ${grid_root}/exodus_ne${NE_DST}pg2.g --out ${grid_root}/scrip_ne${NE_DST}pg2.nc + ``` - # Compute phi_s on the source np4 grid - ncap2 -s 'PHIS=terr*9.80616' ${topo_file_0} ${topo_file_1} +1. ### **Create Map Files** - # rename the column dimension to be "ncol" - ncrename -d grid_size,ncol ${topo_file_1} + !!!WARNING + This step can potentially take a very long time - several hours for each map file in some cases! + The use of `--mpi_nbr=32` will leverage parallelization via `mbtemptest` to dramatically reduce the time to generate mapping files, but this may not work on all machines. Feel free to experiment with a different number of tasks to optimize for the machine you are using. You can also drop this argument entirely if it is causing problems, but be sure to plan for hours of execution time. + + !!!NOTE + If you see an error from these `ncremap` commands that looks like: `srun: error: Job request does not match any supported policy.` and you are on a login node then you will need to either launch an interactive compute node or use a batch job script. - # Map high-res topo to target np4 grid - ncremap -m ${map_file_src_to_np4} -i ${topo_file_1} -o ${topo_file_2} + ```shell + # Create map from source to target np4 + ncremap ${MAP_ARGS} -a fv2se_flx \ + --src_grd=${grid_root}/scrip_ne${NE_SRC}pg1.nc \ + --dst_grd=${grid_root}/exodus_ne${NE_DST}.g \ + --map_file=${map_file_src_to_np4} \ + --tmp_dir=${map_root} ``` -1. **Use homme_tool to smooth topography** +1. ### **Remap Topograpy** + + The first command here will essentially create a copy of the source data, which is needed later on when calculating SGH. - 1. Build homme_tool + ```shell + # Map high-res topo to target np4 grid + ncremap -m ${map_file_src_to_np4} -i ${topo_file_0} -o ${topo_file_1} - The build process requires the user to select the appropriate cmake file that contains machine-specific settings. + # Compute phi_s on the target np4 grid + ncap2 -O -s 'PHIS=terr*9.80616' ${topo_file_1} ${topo_file_1} - ```shell - # Set the machine specific environment - cd ${e3sm_root}/components/homme - eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) - - # Specify machine configuration file - mach_file=${e3sm_root}/components/homme/cmake/machineFiles/perlmutter-gnu.cmake - # mach_file=${e3sm_root}/components/homme/cmake/machineFiles/chrysalis.cmake - - cmake -C ${mach_file} \ - -DBUILD_HOMME_THETA_KOKKOS=FALSE \ - -DBUILD_HOMME_PREQX_KOKKOS=FALSE \ - -DHOMME_ENABLE_COMPOSE=FALSE \ - -DHOMME_BUILD_EXECS=FALSE \ - -DBUILD_HOMME_TOOL=TRUE \ - -DPREQX_PLEV=26 \ - ${e3sm_root}/components/homme - - make -j4 homme_tool - ``` + # rename the column dimension to be "ncol" + ncrename -d grid_size,ncol ${topo_file_1} + ``` - 1. run homme_tool - - - ```shell - cat < input.nl - &ctl_nl - mesh_file = "${grid_root}/exodus_ne${NE_DST}.g" - smooth_phis_p2filt = 0 - smooth_phis_numcycle = 6 ! v2/v3 uses 12/6 for more/less smoothing - smooth_phis_nudt = 4e-16 - hypervis_scaling = 2 - se_ftype = 2 ! actually output NPHYS; overloaded use of ftype - / - &vert_nl - / - &analysis_nl - tool = 'topo_pgn_to_smoothed' - infilenames = '${topo_file_2}', '${topo_file_3}' - / - EOF - - mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - - # rename output file to remove "1.nc" suffix - mv ${topo_file_3}1.nc ${topo_file_3} - ``` +1. ### **Apply Smoothing** -1. **Compute SGH and SGH30 on the pg2 grid, using the pg2 phi_s data** + Make sure `homme_tool` has been built following the [instructions above](#building-homme_tool). ```shell - # Remap smoothed data back to source grid - ncremap -v PHIS -m ${map_file_pg2_to_src} -i ${topo_file_3} -o ${topo_file_4} - - # Calculate anomalies on source grid - ncdiff -O ${topo_file_1} ${topo_file_4} ${topo_file_5} - - # Square the anomaly values - ncap2 -O -s 'PHIS_ANOM_SQ=PHIS^2' ${topo_file_5} ${topo_file_5} - - # Remap squared anomalies back to target pg2 grid - ncremap -v PHIS_ANOM_SQ -m ${map_file_src_to_pg2} -i ${topo_file_5} -o ${topo_file_6} - - # Take the square root of the remapped to get standard deviation (SGH) - ncap2 -O -s 'SGH=sqrt(PHIS_ANOM_SQ)' ${topo_file_6} ${topo_file_7} - ``` - -1. **Put all quantities into the final topo file** + cd ${e3sm_root}/components/homme + ${e3sm_root}/cime/CIME/scripts/configure && source .env_mach_specific.sh - ```shell - - # Create final topo file starting with smoothed PHIS data - cp ${topo_file_3} ${topo_file_8} + cat < input.nl + &ctl_nl + mesh_file = "${grid_root}/exodus_ne${NE_DST}.g" + smooth_phis_p2filt = 0 + smooth_phis_numcycle = 6 ! v2/v3 uses 12/6 for more/less smoothing + smooth_phis_nudt = 4e-16 + hypervis_scaling = 2 + se_ftype = 2 ! actually output NPHYS; overloaded use of ftype + / + &vert_nl + / + &analysis_nl + tool = 'topo_pgn_to_smoothed' + infilenames = '${topo_file_1}', '${topo_file_2}' + / + EOF - # Append the SGH data - ncks -A -v SGH ${topo_file_7} ${topo_file_8} + mpirun -np 8 ${e3sm_root}/components/homme/src/tool/homme_tool < input.nl - # rename GLL coordinate to ncol_g - ncrename -d ncol,ncol_d ${topo_file_2} + # rename output file to remove "1.nc" suffix + mv ${topo_file_2}1.nc ${topo_file_2} + ``` - # Map np4 LANDFRAC and SGH30 to the target pg2 grid - ncremap -v SGH30,LANDFRAC -m ${map_file_np4_to_pg2} -i ${topo_file_2} -o ${????} +1. ### **Compute SGH** - # Append the pg2 LANDFRAC and SGH30 data to final file - ncks -A -v SGH30,LANDFRAC --hdr_pad=100000 ${?????} ${topo_file_8} - + ```shell + ${e3sm_root}/components/eam/tools/topo_tool/cube_to_target/cube_to_target \ + --target-grid ${grid_root}/scrip_ne${NE_DST}pg2.nc \ + --input-topography ${topo_file_0} \ + --smoothed-topography ${topo_file_2} \ + --output-topography ${topo_file_3} + + # Append the GLL phi_s data to the output of step 4. + ncks -A ${topo_file_2} ${topo_file_3} ``` -1. **Clean up temporary files** +1. ### **Clean up Temporary Files** ```shell - rm ${topo_root}/USGS-topo_tmp_* + rm ${topo_root}/tmp_USGS-topo_ne${NE_DST}* ``` ## Batch script to streamline all steps -Running through all the steps above can be tedious and time-consuming. The batch script below includes all these steps as well as example Slurm batch directives for running on Perlmutter CPU nodes(NERSC). The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. +Running through all the steps above can be tedious and time-consuming. The batch scripts below include all these steps as well as batch system directives. The only step that is omitted is building homme_tool, since its better to do this manually in case problems arise. -Here's a check list of things to do before submitting this script: +Here is a check list of things to do before submitting this script: - Build `homme_tool` -- Update allocation code (i.e. `--account` -- Update batch job wallclock time +- Build `cube_to_target` +- Update batch allocation code (i.e. `--account`) +- Update batch job wallclock time (i.e. `--time`) - Update paths at the top of the batch script -- Comment out any sections that were completed in advance (i.e. grid file creation) +- Comment out any sections that were completed in advance (i.e. grid and map file creation) -To submit the slurm batch job use `sbatch batch_topo_slurm.sh` +To submit the slurm batch job use `sbatch

TlVerUPH(&nOUFM%=Nwhx%xUGAB1FfzVJe+u{}HiPCyvS=Ah{Yh{GZHIxj4$DPTEN1iB=C{mi`Pi z#NH4RWhhZd>>rK(b*mCIY5x7EvBdb=vaIaei)>Qq=rDz>F=ALxVDbzr61cv()RRgQ z`8DJ8?BSEE4w4Jq?Z2U}8b+K#6?9VddsZBpd^y#I;2U3CV=!XcKZLahPN z!@fLGK2S!(o(>W&>j$Bk&tXU{ zUfeQ;PEf#I%eJs`GAd}wtk@aJ2sjiUsLW3+Gh=Z-LxA5e17}TyjE=C&J4EqF8C<;V z%!uv7u*>$fWx8+9nC`mWjDXkMhsi9yUy z3P!~Jyzcs2HYU&{qjrBZTgDv_vV^m-nt0VjNWN#nOMZPQN|iPGvHC%D_8Y%)b58&c zpGgFT8F^&3D!Q!;ZR>6el9=MLQ=3E@_ZHS(h79N8!IY@5x<^ly9k>VSRJ{1utkyc| ze0hnHb#M!FGNaWH3;k6s^f&#Y3c(yav_?5e4auCh5={uw%84}1N!qy)r7 zjmRCX*yL91BmU|bFd)7`W#YA~>Hj;mH-cr1zbsIV*%>>C1%hLX4Z!1;totkXI23Io zOK1?c!0}y(N!0NqoG@3_MYuFMMmOAeAtTH8=WF)4^lBv-=#InPBsM}Dg3%4Y1DbvK zp-E5A*>+H+9CIOoxY(h}L`o*iZOU7Xv5*OnupxoNHGum9GeN3pZ8#&8ie&B3PN_Mc zkP*0?kQt{Yty_2{>R{-hL<>btqOWdM0Y2;WPUbu#IvR-cK7|rrF4iizc@z zG|T;Z?5Ive(hZlwNK}2B6{A4Z`uU2=PxbFu`rIECIASzaNf=INs+XY+umZBJI)fFh z4|hTCv#x|1H%1@mKdqb9Nv8MC zeotH;^H3JDkPUkQV1kjL42Fh@Xh3Zn zakghnHjnk55>`uNE)QEdW1hBM3h^@8T=*mM#@Hvv*kqiW--JGnEeMO7A;*B`+v+Ek z*-(yP%C9+*6y)}5_+=+i`+fNLp_wk3G37CRMup>i+t5^ZIuoN>Dw#dP&CzyLsb*a;*vrc|{#ikC%IX9pX-Hvck8v$} z%8#MTT!w0yg@77KJ~t!n!#r(X6kyRLuMC-g%3?c10o$&iZ|Z}qh&p8>7Nfs3j!+Fi zmxr@%YjX$WnG8<|i;JAruhQbs4Iv`?3KM&*M;rHq)lMPeR#c}8mj7|YvVFa*|0Gs2 zs|x>EU5Q@5Ne_B_xf5KXjx8m>fAb2@R$YN7mfKGqy3YNwkX*)_lsCv2%J=NWzoe@4 zef(1;$cL8mj$;wVCuf)!+O)=ej1m9VCt9akd~;La(`lY=r<%Vmha%BQ5ES0bR~_Sh zp>%T?D&p{#JabLjLEAvmXec(4QL zeOVM$)k=CJKRZgnk@Isnwqdl(x(tI`^&;$-m~RwAp@7ytMnI!U7Tm^Lq6dRob=SQY zJDQ*E67b12PtHK`;-}y2A6W-}+9FEtC$QeYze(;{4;SaWPcD!~49W9m`)9 zoDyX2U5a{{UI5yd?WgG;8+=|%mX_omgh-*&H4i}J+s`%LMX#c_>et3x+2qB_3X$~ETbT{MPP_)Kfb{(^q>qkRo`m|G5r0Uz$!Wfnok1VGq}!Dxh{FPG{sNoYCer!Gh7&^y z9-GFH!fa~X4b@OPbny*I`O-0ZFQF}5*cBj{UNv?~3;`Y7r17e|LnrW2?(X_KAQK)r zJ(F5?b$;Z6T2TAqPQ@Y&qKcQD37Ihw>=g`H4e>;j0b-fN%o13)*cg-?OL<0fcViTq z#k@G420J^X6m7j(_--YJh67A?KhhrBKia#$|C1tVP)+4ZU~t&iD2;JnSRb~fu~94( ztZtg3prZxKy$}m&hjynuZFOKsc`TM43D}n{NfDheI!L6hv{%?HlsE$udEs@Uv~xLV zRs$TEBn4-;4a*zH_YxI(6%sA2(Zm{adpfU!Gm4YuTg6x&>lDZ-nuN0}GOLQ_4B^3IqRgAk~%i2%cS>6+|UPp(N_CJ46+5 z&F|shipS>B+cF|Ic<;SsuexcR`hPFWDM^9@r5CH;pE01`?b{J8tO_i+A13n#i}Byz zoHfxOJuh?H)XZ-MB@;|B#PAV#mq%A;b!L_@Fzr$fE(9DgO&J$j_JqT%c~h_N(MjTJ&$P68sa;c z%icwh5thYN0#iMiI6$oMzlF9e-*e|fp0;UE-XK*>2E{YQhqG~7X}N*gGdrH5GLU2^ z1aVh_t^7@VetBD-HN`_;0mWjSNzRyyg6GE7h~0)Jaw}tuJ$S100jQ%+sWN>duU>q0 z(q943+Y8vTs-?`Ek4OU6x-ZJ|3|+H1`)tX~)1qG0eJh4jf&?iTgO~z# z`Q-_N-6iv{#!N=R-8t8SmyfSYaFatArH_<8;CoFaneK?A&>Zt++n@6;YdppW zF2cEzv#Zay*=h#<%X>Aj0p5F!=jKQ*n}w5PFbB@3>$+Z?Y&m*-CEW@iZ#Y=|qv1rcn^GtFpba=lJLosET&)cUC-sG0zd*) zwSpXH7MgF0VAkh21!su_)~+KX^^_32?x1c(t3KyqDsU$ zDYg!h;kXIj`lP#(eO*o4DsMq1S(sN2bW+S6A`jnrk}m|{M4aSU zRlzxa6op}NkPScyG=T6b*s&hB_XfNN;y&6g0Jm8A-Z*cq5*j}QbrC@cnnG#r0U!G6st0cNR1lj?sEe^A>N~=2Be)!n}>xxfSdXAUTn$ zI^a}Wwd7eGU*}_m(rjR#(64um`#g?^CP}45{d|Bvif zLgbTEtjD@91c@=4Z|GKqnTdF-9@FIjy_Dy{yuh1w#JS*fau<Q{1h+7lNN_;2B z?~!hsJ6((D5f|s0rr`3B-~eJ8+=lRIjAa;UAX%l}Y0-4^lQD}6mN&Y^ZKCRxM5Jul zq08{8UJY`9M(G8TH}nR;KH+iE)jVuEScmHkyf~9vd%jc%D|A@KyL+zXs20GxYxdkk zM7Sce84w*TIFOBU8N-6^Mkb124fuh1HHW0c1>t%{&Yxnf_`g~ROyG3s(604Tt7nO~ z!w;~kd%#d#!VI(_Je@QQ3Wdkd&`|2#fn$Se0c{oC-Yjd#*kx;e@sH#6SML*^3-KE~ z@daX)hNodMJ{0;0lM46d`&;^9wqz)!QybY? zu9=Z-GM+Tiqjw~j1c}@vsF$gkOdVwlpN9x~ z`JK8qf`%aCt~kZp9v31X=t8bc^Z_V)HsL&&=L zk4qG_?X+E9{s68VfKVcP;Wr(VF=#=Zjjny4R@H>pir!1%C;?)Hm3Rzj#T=gN#y6ww zJXrU-bb_`_d~n*A>p)h9F}xU9Lt86z-FLDgMmf4nF~UjC^V6`ZKB}%_#kpll!weOs zd9l|`Fr&Zns%@@0gcO)I9KXI~X_4wewNnop0=b?BHV34pR&DZ2ycI}jk+hNOvgF7Y z7U*XZ4RuEKf=)P!&HgeyHH&aK?}tvQ@pt9!c+WkyN|E?PdXtN+HT0V%lZf_^jf-{e znhT_z9%L4kw$Wf3>fX{QR)pK~^jqMqClbjfD;dySO;3}2VTb59@NJod(1!5v-8wp^ zIPSDR;~lIYBp@dSTw#z|RBcb%4$xDu7U=e{eadATp&;A$Ocux1F+$FzLhOwo@!k0)iM4R(>tQ?HAV0 zp%FeW?bZhHq#~#2(x)Mc#wn2aocVciE)PwAH8nf*F7}bcz&LJb<@3`4C_QGAH;HOp zTKb3HffU1R&T1F7*Q{f<*?RW;i3rr#iBghBle@h~U9kH7jlgj|r+Q#ZEv?8V^15Lv zAA_&fHrIS;9nJoBcjL-U6)?(^2Zz#HrrS!I;{!)Lo&*~@_Z=JTZ{&FbE_+A~00k0@ z3`wTN!vQ7dsb0-G+iY<1$>%;fgfpw|R<718M-bHu+zk2jC*VhcJT=aMW%B$7l>LLb zN(OM?vqE$R3x-npcfrb?z3>vY4FPQMRd9-_ zmji=aoFoZqzun0+t8uB8Q&QyzZIe56BA)4TpA_<|CBWpX5{-?sLS2DVGDpv293)T}Zd;TVn57{7e?yODCmDJ_&X}OzO-fOc(ih#f>X-Dd58M z2MJdxqL^1t&CKH!fUdVZ$W9@_Pe~}4hG4`v`6865@5b+DmbxH+WOjnbSA# zgflZQk6s4gBu=SG0IBdA#Clo{%V=%btL0Hr{{hzMP(4!u9Fb{WON z{F?^Lu|OppEJZ^pWMtGJOv6+WknNuXHA!7wcn4=QeQlcU`8LKiyqG(9b6rwFjtU4E zk_SaWL1JCXLTgf?OynS*Ds_Iikpsj33WB2$)uDVdu$M4@Uv@P`)NR)qkd6*162d?E zDAYQ%qESSw&F9Njizp)o%}0FGgX7h8sLwQ7LQ?r9>69G?(>ah_1%Tm*btM-V5}0sN zDZ@-6L_ak`6>&&dUQXqs7+)UcxAer8_tX^ zBnMH8Sv>HK46}RfijTmpjVRC1ls06bM3L{%p{Cg}JXmoD_Q4Jz5`VBuI{L#B>R{Y^ zx^d_C(cL#w&+qNNov9PpX#fDg91L`jm!qtH5ZcXgs40(H%0@|p1p)99inwG4fqiI(6JYuuliTZ{jn`WbDvd}?(&Tj0pC-h%19%v)H^b44j zH-G?=Xu6si#qf~_tL9;JbL|3Zj>Zkrr|pwTUC%ZQI}MfKsT}2B9`MadeJji)Ewe$y zoW|nu=yL+52M&CSxom@aXfpdD(=s0I34j<6ZNUpQLPI;hG)z! z%%?Gjhwn-_>Tu=l9eC*R^rQ~cz9mk_U(^&!9lHHj2HW4%G%kW($+J$v4lfb zTr&|F8Tqlb5 z*}La+yI_2A&aMy$$JT`ntw3Ey*nL(8jap&(|T)k5{G+zo@IZ^wc@c4$tXe-wq<~DQa1roLe?YXy>HSH945=t_{G6qz>b{;A_CS ztmUf^5!#$w??F+An)z)6%d(!&m!FgTQXPU$oIi8D6z*MZzSpA22ukK;RAYWl`!zS~&&7F`Hwt#OXFnB-X z7$LV(qUkCgqps`G!uoqSyoab>cxKlNL=UHZ}Pk*Fmb~IbC8>n++>#sFY`!*c?V5q3aStf*8huNx z{;MLBj@Y+MJ^piJ#?+Q`LK-qkU;!PC_%HvFu5>C~yKLq34?#fRw)uw4FR{N2TLQz$ zA({{&va@C7O+!QJJb}#gQYLuPZVb%GBs~X%_zJRL77*F{UmUO2@?J2bx?z7pu7F20B*_@k||`Egy9UqedbJqE04!8l(>hRV%K-Mx8(V1BLf!HkE(4NuY z@*Z1&)`c>mwGOG>qliP>R_F@KdO!r=yNQ-1D~l9;6?TpvKy=|?YjU`Eia|drA(2#b zoRYqA#fGi#NWp~tKUS!LXR?#c{`Y3d$+7>pyH&qhdlx8}1hL8Pe$(yv7EFnK>K!E4 zTBij*4lzOijEXfZ#Nua%+_kxrlx$k(iH-v@EA8)L zOW5fQZUvImSGuL#o|$&-2H$#+6R7Ml4Iqv`B9Q%TSrBvGBn~r1-m&B-5JEsTCj+Jc zHvoY+2je1}{ezQ#psR zrs-)4&|1sLFY^14;~Pj^L%(|?c(Xy#D_i%$i@@rOEobT`Kr5Oeq zaZzW>nT{SLXbFr>5up6tndopb5zip%_E?^*a3Gxk0d@rS1R?hT1m2bAMX}=Z(3EjP z#WcV?HwY9A-ymLV$L>zBAiDxtO}Id5|GWELAKB6GI`&fM%sNAJzF}KD^yVaxl?2$w zzWe^tJ~|rfmNBR&YEvS_G^JYNnWCm%N;U^ ze99nlfVpql&oc0{SplE)RFXDjcT9iK{xU6wqt2|kJ>;tez)WxKIxL1mL*1d@hauRy z87B}r26Ie~rR8@8vuXfU>q@xk+TFp(gzyWX-WUHzYWb!6CxQuTI8d z)ON`k+gwT=$%ZKDm?O-_ET?wo-zbX9p#PAm{-;?9mbB56t;mDJd;WIaE`0r1LvpYI z3Dy0eWh?zCbcpDPlqTM(iSmU4@h(vp5~$E6fV`Vg(7}k_VE@nk^q{Co5k)fURr)3b zP0an3ODOYqK4=2qA{t6!0E2QOI0afufDM#`T^CAJN}TdT-2 z!h9X+bl+J1SnEI1&Ykl(=VkRiw@RyC^riMKcRu8ZmhYgYxaoaDFg-I#R*c->y6~#8 zjaE9r{>Xe4_ErtQ&MpXy1eKQ^Ujc_Nc=SFK<>zIfxMIvQfg_Q9@+bw(w<(8zrF?K- zWtf*JlmpC=fBU%=2Vwg^ zyDZj;`Ip#IqWnJAeUX0Y3PK+z;qIEg%oX_~!g2pL0tqEkaVsEb1+LWCS4b_^4csa+ z-(78E@*)OM9KrjK=u4?m4A){tNF2B6OfnpwL@lhZx;lW<^5TTVfJgzqZcCtJ$|B43 zg;&>r8~2XB6oCzjeHgEBo-UHuSpK`4sd_g6<_=XgD(yw4h!L=#=nDF`li`?Q+PC=C zm2P-s6B@DgQQ`cXL^lUuJyb{vN^TaN{7uVCc(T-K z5Qj^VeXp@yd>!Bq9<^I`2f&Ws$Hx6sf~$dPbQ#H7kLIKWY7vjY5m*A@?y<^019Pql z(aAR(6%DTD#149V;Xsb?BdU&;g(81NTqn~A!Xwprg7i1b5-2IRI_Nk#qwokczQLOk zr2WzWNIlT#>f6!xvr`F49Msg%a>kuN9vkYar>Nwk?! zWxkaJANL<-VL7U=W?%0F4afBKid__91?7Y$FB(^)!TfOToO+iud=)&id?tA0xDvT zO$9%^tgj>(7fc*Z>_r#;77Lg*)xqXt@XvVrZh{H*<4EU)$(5-EST4t^YJdr3Td?F> zp;<%Wudq&Dx?u-3E6rzK_Se)V@0Ky{OuLpmO+gS=sv@D<6SOZ37+|$wKLT~sQd%K} zh8&=*J@_U=1s1ig5^~e31Qswt1|Rq-x@*Q!mCXnX4ZgXkE5WGk%=_xgap}0d;d0dp zDe@Tl$D1D+@3F^onICbXjg0%B+ z+}~FpPd^8ifIP`a*0-y){JBjOJ5;CW*&`k2Q|3U^@|vO4?f^X-FBQh!cC5uk7_hX+ z&iGbhOUCi|FxcH&GFH^pP{(1DpGqwPZ(Gh6CNbNz7tU}PeFWHUfPfIHaj>0^niV?$ z+2h+b^B;wn#FQNr2}|H?52DSNYbrjCX38-^4(7>Kf9^1+u2=Z_0Y|T6G$b>JzV?{t zTo}o(4R6VaXjaP5JgOqZR?A-|w6+H6v@ZMivoQV1jqqjn;|gFlmoY!jt-#y$GX@D) za9Gipb0RZEVi``}Oj;k+@`C+!A`qMBN!|)0!D*yUU3U7Bn-5AqBt8R6#}I%SeSOEb zi-(XD^<1tH*Pv;UvHAS0?7#!07Cry3UXSIK2YcJU7ibtxS>{un~E(h=rjLaomg<~@VI>NMOqh;36snQrMxbH_@_tvkdL2ZGwBxnynmt_KEL4YP7z#r=iK} z>>|ou<{o)VoI_WZmc3dMQ)}xx>l5oSpWME%Is5+^>W0qIG@l`Lz}q+;Iqz&;rkixG zdChrUyw0l7-#YL+5tIU%d)Qt_=K+aEs5JTt(R}t?%Odx=Jm0Os6`%g@sm0AImItH! z+RaKKAXk5XD1f#d`#yMPAgB5~K@6^NHSTbo$F$3J~+WY(_q< z<^nb&dWP-~s$CHpLxHb}W{EVQa)OE2R8Sw*NmRp!5mr%%0a0qY6h$eb{#c|(DhzF< z3BS9KeQX;ZLL0fu-&4duJ}YicZU5>h`0zY<%%nYB`RY!M8G&38kP(FMd#_5iKMbE3 zn+}Mb4TKEpLuz5$e_SJuJ{C(XECCwgzR+RWA zKWtUks<7bmgi7o}eozy`aSSl#<(KGSo}{!OIcHB77vk9v*B_wx79*}tlCFfFYa@=< zHd)H6nT=T-=i3#^$C1(#%pa8okx7jC&(LlH3HnF1AhuKX71+I3&5Sb!((@Wj?{a-R z;kiMqI!ZEQO-SA-cg`)*sxf=VxH56oY~b_KDymzPvw>oOJ>VASNYTyhwjcOOsHuef z=hmEs#CnduM@wkWv!7JLbl=?N6&f^Rq|&wv{VYgm%&{wEdbz{Z5-$XB<5!7_W)~ZDf;Xh21b15<+Wknst`T39=wrnBQ){9Z?JlKyA+TKvl$(Nidqm z_*2g0Qa`rXXjbM6Ya0u6khIl<4qlqe4{RWJ)g#PkFS^s!MlFTaRk=Arj}mLI^0d}Z z(CFd2FpOj#jtbmD#LE3weZ+BZuHTPb{yR%J`-)z(_-%&c#%Q3z0KVrzCvQC%kRV7x zrg1iKkR6bo#BHFvE}7C?>vez9H|c-O*o%hod7{V5WAY4Sx9kyjH%c~Psy3zBvd z$GyQdk(d!L8rRhkVf-B(NiEiH&roj$1Ml=u6K@1$4tL(|CAZvC$nctJTd@m-bKAma zh&_F(=;4Eym!e%t#CY%#D}%u*Jlh4>tmN{cPwFA~4Gyw^$6)?Q9E5A*5p46cq?kQd z4>OUVD@y9F(dOz7mB+mZ0<9MSO)SO5TT%qj~&yZcB+3H!2PG-C2wfYFo^yi;S*#@RASD(HZ>&pp!R4Q&Ys~Qj~n)>()zx22IVB!EB>UjSJVS9~t53mC*>trWHYF@u6L`;0mBGV^Gn z>`)o^8|!2aeU+T|2Ve})Eul=dMkR3DXe`V+keTOI+@O%wX=3VyAg$JD z0}zgm?79rn@;&~R1C$;slk3K;)M;DD_lf2(u25WER(f=Ka^JN@;NkuZ?xW=I&p%IV zYA90Yjfti8NFF?5vmtmLRnh@G}oAWWzEv3Lz&}%Bb za^SM_Kt6dubK;9(6aR~RlQobH;vE=%w&_N=Gc^;-FWh`m^*2qgGH}j$PE^u$c~~Bu z9KQz&REc4k1~9}%&?H#lf&LePNkYK>Vb(8>Kk`;9@qB}~NvioJtJCnJaNw~a50p#& zN2LkAp7z0};{Xb+lV0uABx8>n*5O^$4f zE5ke4$35hd%A&R9pxQKu&&gVc&R}H={@0c@S#fsHY^0Z#)Ni;P?rhBB%yzy8Q|}=uYT<_Q zo1Uk?kS*fhx>ru3w#pq>ywq%EW1^ce$&+QH4a$upkG z&Y1fO0E*FYpld8NJC0BW`PX4nG9d>|6b)ugXmKJjgP&Wa9lUuEIL4uXvFIXFl zgA%j3ual^#E8AxHuz`0;7dI;3;t71`LfS=w z`Ft>K$zc)k$>N$S9~uNKC6jOoTz;3u2JKB>gG5VP*w8RG4z1pX&{2a05q?0+3wFl?<8ae zk!Sq6cEmROE)nyxph^?>cbQRK&4htafhRw84g057-~KYjAPxB36;%kLFy%7^I0p^c zn{G(Sr^r6N=#NE>IADTaA!UYW5!XKJJY_g5MB|Yj|M)Qds?s2LKYRD|LJTW z)Gna-!4k(gr;N`n2I3-Z3SeM;LH-jBt(mNJcX9`w!-EGRNaErvvnh2AFVR~^Av^4- znvzlu5(8Xs<5loJ|1A9grA_4*A+2)UXPW~ywsOOIFWtEyD`0LV&?-K~vMqF5 z3ux4CZF%Bh3mm)*9~_b`$gQLpKm}4NYZP(5Dn@%{0Jh>zwBi9o{vkiY!-S@d-M_L22 z1vZMe`$6xK3fc}DwD!AIq!LgB9d78-*puvg&Ci3Vn@fqh5GognT0;ws@`jwoN_@93 zm69+pS*om%o=%y7U_A09$DW6rvVJlb9!ZB%;mc8|0zIBX2{;WPdJUpdiUNQr?>36E z1;ViKi&vT*;KfyGK}O-KU_?fFX8U#~GvR6l5$PUOPb`dpTtEt;2ki}E@kU8M0B2L& z1t3RP_C_dsB4`jfu8d0TIlKIISByN>lQI-ga;T4{t)QW2?fqgcVh;xOcQvYWPg8^X zcIKu|@*;0|50j1odatORKiU`ep*C7&+T%D;ELC9mLuqRyl)+gznSQ=nZ}I=1Y?ndK zMY$IPupT(&E%4HIV2fA`J(*(rpOdPjB2QhVs5$#|G}>(Z6)re?52ahXGvMadLgoz z{%=X3E~Ee7`B@gGN5V1d2k$3>m?EJESf~O@t5Q8$!g$BL`Pu%h+g%mnW4bEP)Yci1 z*byXsZG=z{C^&b!L#(0yxxKh^gsN3vb?Jm$FWo`!Lm7a{K!X(ewMR(>B+Mw~7|Wa| zigk@BMO+Nf$0wCL{w97cp_^wCKO|ut+{Rje=1x;QzhIKt;gopg6-kFiA4SrT~nMz(&eE=G^QvA?{dfxq` zh~N7uAsSJq=0Q4IDm~W*d;eHf2z;Hb;LU0?@K$Y00B)cdI`Q3s=2pI5;2q^lcM4$- zxxZ9E6{q_+F(v@spSnY_vWWS?S60`+EM294=ULNL!^<`Fu^Lbhe=L%#G-PLD>VQR~_SuME#W8xVy*BU9{ zB-$;vrwwkC;PszrK}pSdn=%>9qE_GU)- z;Dr7%I~ChztY=zjW;l-a16Xc$ThOSknV@P8YJfp3Qp0a=e>M451iVz@VBrlTt48rS zXwTEAA#AryM-b_uWy};0ghbO0H}3_gr9ZZ_YBKyD3jD(fBvNu9X@bu+(A@Phb^9vw zl@XZKK!lC8wBSN5Xd7laE5pS#Fhc_D89q;KN)Qawk&1l^;Bi$bpjb#kTiAOgmLIB; z4Ii=NxnMQ7IcG2kx76WFuYLtzSj=qJ5c|s8clgdAi;@>a(OI zm*wNKKf9rRn`ReNUyRDuAsRB>lx}Mo=438itI`)raTz^luad-&4|;VQ)IA#I=$`yv zg%{4u$Nd0I!-7O`c}C8WHU;YBIKq&MT-bl1%KnX;&=Qb^k>SIMn6n6SGULmT@NeBCU@2?}?yZF)Tiuv1A>~BSAOO!5wd(=TT^Qqw0OpU; zg4&`HH{eisHU(>auP^mZ(ET;sBOrqkY=j=?@n|#_r4By(-buES7_7-BGWs7f7f(?` z4a0BX!<{TuC9=}?`B4TwUK0-3oHPJji4PBc+)-QC)FDLEM|4#Io>9}kCteb`=MOFQ zs&i&f-+}?rT(f`>ay(!ILrk5q_B@ooqi0Lu<%yqOo)}S-Ghz;Ys)4;Qs2xZnSPf(8 z2DT%I;rjV81v&4Ix);(@$|yqtFf*id5Fid22w{-5)IwkF`zz|W^pV9b5}yN@AZgv* zfg1qJJ&n=}tl#8dmfh#?b8+Wu!QgbLwx2!@rOg3^axI$E{exjXkuC>leUD%>0HV4* zTj@eL=iW)mHd7Bl@9~j0x##ABVfNF_#ryHTtBY^`>d4aD7WsT4alQG8kd$sBfr z0}W+2Npl+vzJ~kP_+AhF%)Yp=lDaL&T5~@_t^i$)JOD_`y6IIMW>vtMsUg-Nmu|sU zl1j-~EyCeFHJTn1l{9T3f+34;I-@4U4+`rj%VQHl+j4-|SQ&2$0&k(0rfOX%-Xu_f z#1VK!A3V5wGfDIwTfmzr08ErAE{3@<3dGRk!;ZIjnak!r3ar&{Vw%N0kuwk{*^`{! zrizh}Ro7jTHKe!Ft}Z659bsx?gOHnvNGcuQdO?iYY?m10*bOg06oghGvw)2lfcx51NGKKdi96<(hM$0u+Fwe9GZ8#9tY843CbMQLB?mw6G zS){yTz+q)2!P!Z={GG&{fu#D`FVR!|{&e&{T=3(3WL2L#XvYt+hpQwk-@n zkCl^G8IYq9sPatUgd8o&xc$FCN3tz9W5+LC3tfT_jn5JV^kT_ zpaV+VK2!~EM{v$_vMfL>^ZB zF{z@EZb^sNi|7nqzv)ihqEGN2jt%RaIA8XC9*9f^Cj1{`EQVvB!$?)$Ag=Y$V$`BC zzD|=b0K3(U1qAzBXF#rTrs(`T#??6S2_5__x1XAyxCs{ddSKr2Sc=#Bw$wm=#5$XiZ8cQ8ZTI{%iR-QlK;ZCdzqzq zui_md^>?_7oS-jv`n+gVPPb8K5&!{uq?xq)0V^cTzLsK6yX=`S*Mc|&-Qtx%!NeLy zj)zl!N=ezNjH`#p%H$y0KX^CKr^CNqp!W-y13D_eqU_24iPJl?H!f4=OIh^QT0a6Q z6Zm)Kqq= zC1=u~zy{oBhPX?!tx6+}15?u0wwy2*rd|BFiBd6$oiqC0bML4%t_q(eRvsqk%TM81 zKZgu3EpY1408vdMRx`meB;}9T8c5KS%SfI=x^wzX7I6gdC**LHhzu~R+kJn>C^1&b zc>FTK@IKkiEq&83EwDo0-3T_vM^>D1GI4GCdh<3^xI_6D$c4{9XaBEcN(!_E`KSI| zmI)!;l;68y38&#U1UHE}y zMC9}U2i6CCH<$^M(PJIa@0@G<(eO(l#Up7JlhW$zpASi47wmRlYZOw$jk`j#8i^C zeTT^On>=EeCM?wuZOJX8Jj5DkXv+0X!E~mCXE?s2{3gs-nx3wHDP8Tt!vgIoMVa6X z4)1Q|ojaEZpRww%@s1rwwROkElqlk3!pOp)-o|z8!Iq=epMi{$+8;z2pDJOb!YEEj zUAj)2>J^*FCmZ%Mz#33SK_6Q@9EASC8zT&5n)^v!M&FA%qi z!Y3vVtHl>(q}vn~g+e~i?AKuqwv2q^{A-OT#{PZ<1CW<$0ovLSJ7!u95f(<6-nex; z;h+-vEK3%US&y9w^BKaC2kQ58ykMq+Z3X^`kAm98C(s0kOW8E!$#zN&Yd&hf@@GW*s?kIQ|VggMr7g&ymz2boZM#BGz|ShES%yGaehRc-P?b_VcUK9mDFh_euA^4J{d! z=A~|buJMHPi!k@{y-~vwRcX$N-m~;A%aSLbNwr$sUxG`IHTssd!^*C+G@qpGhG05X zB|T`uqed}p?-D}QXJSU`A|a_W57(YBr|sG9AX)rS-#IDf)Ix#53&$VS8C2{F_8w#7 zUI853)!=rhRgV#@9Jg4Mokp+Iz74HMH)A3Ux;m~V)i~?p6hOc#H36mswMb_>oL3Xx zFdwRp<5zQv6UxCF0*C2hb0RL%UgG~l)|3#M?Jl!|ApQkuK>ooEWGjjOfLLywRfrte z^bg=R4Gj#GfDi;Dm{N`dbL;stgdWR*V>>{ftl9-QvA$!Z}JV_35PCa3*Jb?ZH5;c z_P>t8kiDM@AeT1=gSfAtTF*aATfu=BU43}CmYwk`?i6R$WN&#TErQJw)=r)L2fJg0 zc^F3eA{Tzu5n{gFN-KaAm%`3GIR8<+G;4^xWWnq{b@i{&-gRt7_m2n%O>rp!dTluv z`wO#Mm}7pC{`dp))g2I%(<{yC7pm!Gj2`P&*|Zc0i3c=p`>R%EpCg8)o&@yk>iz&H z_YC&X9^Y4P*EP#=<)Xa8a!X%dlglAS(lrPn)Zt_hnO)VEqwh4kI^ZMYb>K?q zHm`-UK3*XHv#Cs&{(_j1$^h<{tzr< z{#y(u(-RbM&Q*p~-vOKr3AaDt)o`>E+$VP_dZpw&{RZ?n-u8Ky_LdRh2h{Ksq>A17`V6O=JaU z@M~tGjNW^;s~T6hAPqm?SJtQV#_rh{)U;| zoI~TdUX#vtK$#cwVJDwY56N1O;mEOhdjQ7o4_LSE;hA$Shv`H%57Qwx{%K#-mLaFvl8_5w~^w zvWjdX?ULRIz^(OL=@f!!TMY-afBCjva^Bvp*?lF z@+1#(q;qNPBD$D14f_hgvWt49@vc)@$MpHGKmd>Qz#FVWgl$#!=m0-36#2~T0iiJ) zJVbLNm$;BsUS${4Z)F*<`nb6(^3C&^`U4Zf+PS_ig$7Of z+f@KoPBr*?H-J{P1>r*Ag~O zxH|R{@@STzg49c@w6tXV@K{Gk6gBthMk4EK4n%|u(2P|d-yyzsZhx`do9a!1SzSR9 zhXT2?}1E9zbgU^c}JuE7peI|WmOBo-DGY@qQ`G5>LWI?6ms zAQtHTZ_#%FV)azSxmsvs`$pg8vbs5UG!?}spOxhL{HPiWj+siNDZO%{P-=U=i_o29 z-lAOsX<}y#kzJVHvPLGdsqn>la#K91eTo+~M~+lG@c< zy%TtcrbC*&m&$9`eH3oe zk{3|=`Bat*IQwCtSjjeOv5N?b<_K|Iz+orz2LjIYwCYD$_TdDMx{`GOfC73=TWgdk z@)esnB_4`~xY8adDMRc;E#b>5GKc+NPuy92A!a&>JPj~H4C@fn9HRUY_nxwp{-|P6 zw0e%?<34MN`MB`3&|D?NuqXue4^?K=Yg$7B9BNBa#uRbR5QHtZFfrRnIS-at6;?jJ z$X*v<(NAp6Y9zR;K7lquS^a2aiwagZZwi0l_yo=z@up&K(@{B7uA$-uU%$e0-lW`t zmtp|gErQrlSxUaF)vJj73@qfRQ+Wob9?pih-i^c<@27Y%#Jo&_t_qq`r1%bvAL;n?xwg1qq;^6>Y4n|K zXyA{Q?Gx?mp?A3{Q6Hg(ISd91(o;T ztjZR_4-T z7~5?wba<~aKa*A=Z>RF=((P^7g8ZzBVfH(x-4qUFL&!*ssf6==T?`jiOw#NWl=%be zTHk|$yiJDu`2>==qbhx5a6|+|F2@EcxPhx_DoCQ?yTg7X^=#s zov!|YpbMnS{e65;I=W~QX#QL^yfB~*v?3RcH9m)h4v#4{yk-C-RyE8E} zCEd3|U32+hsJHsTphRTY*K^MbwS*u&i(bYn+TdYe1m~ zj|l1PLx&K`t=_Atu~sv1e}(7DKQ;zexU1e4B8( z!XVb^Mp~RDL3d7+;+g03jtQqJ5r|4ty1`K1c-nvaGq0ZWGQXc;@z zR>)|6>SqzfCr7#?!02vDpUO$NXlfKb$m&A+9H;-%`pHXDHyK*G*AmXJDOD^c<<%ZM zS$`kbk%%pvW^(?p%MhUHtOipIijhKqO+-*bHc;4vXt75a*Uh2W0$XI*CSu)`2gm`@ z?DnHAMu5+JSv2MPsX`if;1bj+>9UO#_B!Cc-&dBWP-ybWc;Cm4J`62Mhbb^*^G`t zv`!Q*Fn5fCkd93L=g2w@M0xZLX|Jva#ugxe=Jp((8J1?nivGrnN|M|Ba^!DD;Q(X^(ceWs|eniu@v(nf9mDB?ojrqx_f&CKICb zro?h@4~(-(wy)AJJ5Gl$z7_bUe%c(-u};<*ZTg`qafzp*WfauO-NtI@aW&l#V6U}- zsUUiIl@CHv81o7DITjDVj!i>jNs`6fC|_!&dwK~UR^*+HzF-mfF*$3avVoioX29BP zKIMJ|#p=z6qZZF=eicRxBYETXM+!WcncNloEy}KLe>o-BGiovB)Dy@W|AYbhC(`o` zQu{ zkzfi#sp}sz(Wu_;qaQl#wdtQ;swL~sWRfQR5(U@*(tTJ^paBDz7__$Ant^nmD(oze-F zN=pO!hQ>Pu5D2YQk$_J`+&Jatd!x9nBvFJ})Y0_}=cDDsgKgP`IkD z01v$qdi%dt%O-H{mxF$~iF@eK-MQ!AFs+Rpq1ETeT}JDDH?eWk6ipYb8tKIs>eH~y|0!kF z%MKWfE#MDg?gVo#MH+w@8&_eb4?q3WZt4O8usxC;i5rYI-YhEh_-?KN@8CS;3DT?@ zcdj;Oo9(8wsh3`+{bXW^PdB6|^)4xZ&TB}BkcmP2^>!b7060(o4N_J~Xse^hAn@Rxy|Slo1UhjN2Y-e}qUzpaFHURr@Q%&A{rI-~ zxIgHqUZC^jZ7XveG4d`+NGvRZ(JX+x+9Q81wO6VDnP2k0lrX~Lh`S6CVP`y&nihaH zO9%?15NHkFPqDs4E%ANL_5ai5IF|*&axo!d!2~Q!mr}Z)!8mFsa)Xobsf958up@$p z5*pMDvfx5p=S7%=c(RPP+*NJ}h|_<{mH-&mNwJbi0%gNCIqjK5*8yyEk0#8{ad%>F z)4!`-lUbz(0;ro-}EZ1`D2zF66e-*)4%hvkY`1@&h&U2h(;AD&s=xfuuQQ zA;IGgpH1VDbC^gawB2_MsdxhiL^x1HFhBr0?hz5ke(bJyi`SMSLT#xd z2tsYCB{l>cP%uM3#0Q3!%dSugmZduz0Zjp%k|>1-NL)u#)*wmlz0$$WLW#NnGk5|i z9)MoTp(w~t>a4`>x{u12@5(Lxk}$sV7W9;qAx1RsTsa4{aaULUF(EwXySMxM2aY=j z0zx8r3{sCkV#fBTk0HfhO7sFmE&S==%rVpR_XR5wvp&?GnwSWUL^OjKFu7_+1&JL( z;sj=pb_03zJ`9t*Pre$78tMR|*+MfsT0fKZ~;*!oE5 z!p^_S9I1xvi!&Oe$y)I+x^l`7ePLu@2F36m!)`42W$?#}&#yC)fcGEal9W|EiMy76(J{AMZ$ zTPUVf;u%@n!<~*1WV}Js@Y`PO9LQJ8zOYQ}*>xdiNBn4uP4?b5L^!lGBkhmCC7uS! zZ9FO>8|f{=WbmLk#I$B5P<;7}oQS2iP3J(hg|%aL(ap1<*c`&lTjm$me%J&=0`{ZG zjJ!{kpY~P@R5DXt4i47cU z5ZG6`hYDEp5WGh300o|^POJ)XF_E+4b@-#$p2QHJbdsaqSpe<|2&I$ZLgdh#WW&_z zRF|V7Sm=1b3)lp2V*wF=@yCNMPiZMXG}5*di1q^$y>3`!Dmdz%4bC^VKRT&21&~k< zs;QJL((p`Q&8G6Fsn|My7a>a^-WteHfZFStwE7X9yL_##!pw#HVC)zc6f?W1qf-lv z@TegIn!Tc8l*_dXQ_m~$`>X1uvM$E!gzsFioq27Lk~dZ7moLGHE|DFV!iKnKM-(!& z1A}N~+AW0irpv@oA=1Mup1GvkaxWZkVNKt&ZF2>>OQ13Y2AX939DqZ~*8^>+mrA@L z@yix5+Z&QCZjo9;UgK%+m#0O#4Od~lZ2GDTJoDe%i=j})!6aFscyM*QtMY%Nf`54SOaFKN20wx! zrAK5?O7>+n2Da9SeiZdq3W3{S`@t$)62_YktK&HdjIA`!u7I!+vC7j?-0WyijQ`G> zUAp5bfskphi1fx+%QlM3&9#L9LVuLf6&D9iDW0PP&AoE*q`OhPnTZYuAZ6%Smo^ z+&+LqrUQQ_!aqbC&C1xFGtqF>?rAHx2ITuxL;Ur7wmdHEJ^#QOABOoU3^>PC%0ZXf zMObcRUKXt9R2)^F5KyUf+MOHRhlmq-i&goP{l7fE?Hhn66UsdK_XLO?&F>t@##oI`mnTeUU0pej9avu&%h+k@Q1fr8$VS90u)^{gUUr4Dn=%~lmB}DBYpw51tXtk!G%3x+IzfeK zoF#OJ*t9hO1&5$BiNBKg$~DAzA(>(GSt)7M393ZXl8t#H5(LTZXGwBAYj@7a>dksz zA>v9@yST(=Mbh3>Zm#_5*5E0$c~pH66G_&RO+G)Q?*yO#{<-`nQ=iGB*81_d*x8?(gvkMx_uNlyy^k=C^~cOZL}&=Mew=)y z2^*})y5iT3iIz8^`t!VtT%j4Q@3{|qnCO&b8vskplhzc&DYP0}HM(BRlP|$wQcyXk zQ4;HNy6-3j0iJ0E$BGku`$0ry57LVR>0sBysrc*5mT&nbwjegn6Dw^FwI1ivh|#)f zT^zQj>2Ez071nF;M)RQ_rRa+@ICr}>vPZr2xGF29mX$57{$Hwq6lPJY#^7=JPcm+F z)i-m0te(K@ZMlb6u|b5~<$H&d1u>0Py2g9*#31TSU%t;L=~sQ7*Ea0R^VdXS6zO84 z9gRIh%>Tq;OUpmaBr92kmU+swUAF@wvauE#)fASL9vQ$?77pPc?`Um`A>QHFmZli0?KsQjOlJ1$4&CSp68R3* zk9d>dUi@a*B;1kTRfeId+&y)#i_~%gTEiJlSH`w&y(Qb$i{>|tJiHrb#e@eKmjL`^ z_)i}T6+~t@9pMK#l0+k{GMWP|aJf7rCAp2MPnyNR8V{=q6aW(#1U4WDhNc+!l#!pV zWKvifV~OjUD56Rr?Cou2`bbSPtiZS^b(>Jeln?TN(@{(9h=DpE*=|Lboj~+X4fta^ zB+lnA1R8*eu_5haG%ACb49AGuJ%yav-7RnZyZZfj^AL>JYJpAASuE#%D|ESkH3&x;A?MqLvF+w~+k~wI0YZuy_S$>jVi6i4DH|L-PUk%(m7TZ|7!LZfdj>ZQEwjGA$Dk%H@WeMiu-34XIx#^Aez#oj{XMV5<8i-4gtYM(gTOJ`p-Y25 z7LqUVeIv)?xov&VPXnZt;rG3?8wBA=G;5gA9`V_2cyEF+fVYHzB9?McnSfFILINVJ zkviF%2W*I(dh5{GhuW*A6~^1nDN(^2!iXkvI(H5@G1^mE_ENWZbEhqo1Y)gJ^`kco zFBxPWHgd2cSsxujJauKVyX z9GAQ?G+-DXfc6YR1aO4n6QVVP(GC9FdqPJPI-8I28;eBVlgF#?X}<}5-q+%mOk<=P zD`n@!44drku$MG%AO&r?194K7X{}x`=A!~??X93o?ns-FAa*p6hJ$GlTi+jYn1@JDmG<5LCO>oplJXK#NCLFFpElS;7;v+3nn=)*%V z8{e#)=9~2XuMPypAs7++i;-jf@*M~d86v?;WM1kfvHaG=mQURiQbBd7X}pw$6aOv6 zjw1PUDm};tY=@?>k#7nP?$l81r(5Es^w^j3%bO1No$ChmC2vv%FNtymJ4bRHX!~x! z4}B&b(kG|pX{P|P@sjiomMI;-l}?hp8@4zjx3wHd0i6kA_O_lrf@*tGd|TB0fc9-~ z#Ay2~uzsVA}kcMfo(TkuYti7W9ga`m=_Ywjmi(bxPm|7#wD z&F#sBP}Ec6MJ=j#EXlx8e4aF*8}m`gX{{oJ&f0UmT?Jm&@@Vs2VwY&U(i+=}zVF(N8234-50KlZ1xDTJ8WVZp5#ra2@H0>odq+PXWDxeR`C|ZxwjWE_X-GAC!8P+-g~*s* z&C~eHG?I9M4|&fJeC~bQ+(X!PrzK8r@g>{kI$@)c1AIGKn?6u*@TAS*>#jYh7-2&A zFc}-8nf5yVm-oyn!1E52negk z9`~JaM(S3Z1sS4Vym9frNS>QQ1ORF4dH;+%z(JOsFh`N_G`nzw^?n zYhp1;eY(1I(UR>ybY|7{S}IUQ{_X=Ifdj^I^LgG`sRe6TvF)rW?RPbuVN?@sN`qph-mb|MK%Y5Jc{eBz0W19N)D~2F**EX7AIxO|lku1T%L^vfb zmzQHwfZd`k#5PQo;S*5%7)dn1ulX9mf~79nufuni!m-YoA!~J+3|aPVShddd#kmSN z@>oxo3WSGY6`FPoIjVQWBRT5^3g-V3Few~7rzK(vZtaN})j-<&V5YL?9%P|;4%DM3 zdZN=?s(pqx`uN-9@)rBvvOND(=rwpggT`VL7FAgY_ zOi!6TPiQ|agDS;jw!T5uDQ?#Q{afG@lJ2up@$M;hZesM&(Ku_+STx+#Bql#12elif zOSy><%G_3#piTP;85xOwGX0I zNyTn2_xSu?y1P|f`O|vLuwgcld|(j;s=>w;OtK&t(O0}$(I2e+K|$LiR5qHNy?|7^ zKnlJI)1ppxBjg@SIe2l8NQT!N+bXrdqkgC!q)2<#pin(f*eOP^&D&nFik41Ej@LjD z6hx0l0MH%I3(~h-X7G;x2>!?Ms<&8;-DLUq zb+Nja=W`yMKiLOLX~{yW$Mc^w&?Dj!6-=`tCN!Oa+g$-<4|!8vNbDD zr4OPrzCV`;O&K<)f*3ZI$xd&$_qEL7o2=(Sm#Y@uGe8$gQC;7p?8fL$f1pqx*o&>f zuF=^$n{>tCtY~l800e1n#+&>o{R4p~ATx3dJ?%OQapF5lS1CtV@rnrS)tXZ1?EsuYtkge=(8t$$N@k{{#@njEhA zXB51Jx2`P`N@~CviIsr;0S*)=4}mK(x$C1{ck*Y7jb?&uBA*K9E;s{TN6z#QbtdQB z_n@HJtjzkZ8NDGH`xA$hpNBJ!u!@Pa)+yv93K7#m|AF7pFOun#R#MnQ-2as9a>pf@ zSqb4_j=6jZ_NQCQJAuT06&qyA@8Pib{6@b7q}?$HAlH^`U-hehA_o#k9ie?qC>RSE zGL8YS!n=ts4uIhEQUAdC5jZd?I))u+Nq$vNb#e^U#JRXRW@wHG-lWnt24n}_6R437 z_psvb1_rGV49uN#Bz|4Z(Krk!Uy(;Sf;eecfhZOEo#{{6(DZ-l?QV8F92uGA0D9@2H=-bFX{kv=wSai4Yh~|GynjBXaOb1f&|44bLyldqGb-E05hxr F004tN)$jlS literal 0 HcmV?d00001 diff --git a/docs/dev-guide/adding-grid-support/grid_illustration_ne4pg2.png b/docs/dev-guide/adding-grid-support/grid_illustration_ne4pg2.png new file mode 100644 index 0000000000000000000000000000000000000000..2b547436eac838b10810cc479cdedb3a2323b0bd GIT binary patch literal 108214 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ⓈitzkscBIY^g- zc$rQ0)0`Sbg;j0iE zwnFMyJsJT1v2qi)y!v(j0dVRH2g()+ZXrOYr zopml2m$|}|O`1h{_2=F}oifCf4XTO{n|HASDnV6iiK9}U?jHl_-H#4Nb>EymHrSzt zqX!jzLxS{7t52C+k_4^Tg4W&aN5!)}Qu8=4VZT#_vDldJ?#&a+6F>M z@oUi&$NcMug`QYabAJV$c4++EFyZh_n*fOJu0L^WmlaKn+o&X19@I3ZUB0;7BNapa zYTJh^6c^#vQF(u#2p;OQaC)sXvzJYMgg2|&fFk|0DN(fjFe@I2ay7WgHG=6G>P1ir zLJaU95K!DmC8VjVqGy|Z{lE`%XGGF%2UKbHUw5`o?MH7pt1tEWDm>Y=+-%=+8Zf{w z&RuV=jwewqYz%$#0q8fBM<@}l;u1EmK_MsH8sJij?C_cd|bdd+~s&Ozt3&10FR3W}KO#xY2n9J;~T8J}}qY<12y_6o?tP0mtEXs6fWFMGfgHW)~AR0)2AmTL(j$*8WQI=almg zK$2Iak(=|AXqoiT=&-NC))Vj@i>UZqdMpSu0l;l{#7gI1i^3!f6#rOin@oo{7Da>J z4PMSR6;dJ%hes+xOl3L%HB2_EpxBZB&IgLId5%@jiSgO)NNEygZ}NctP0RubWMFYv zIUnjk;RDjbwK1IMf&%596i>C!^i}D30@kxZyZ|Mb06DG@eT|FEG~}}gh{y+P99{Yo zz#Avep)FBGX~li0F}nbfU$k1_X4GCOI!{F>8NYCxvkYnn-vp>;AxN_Le<`a6?bl?N z#UDoJ$C?$yU7jTDmBR81>b`&N=2!tZCCA#A2<-F=Hw5uf8f{As9XvIAo;5PVAdCsI zrktd0da?^VUkPzMb5HM+4SGABRfxP*3z_)NeSZ_+Yqbt-uDAPhK)uyW8of^WMv#Oc z^0S-C?ZCB!dP3+GzMAZyQQ9!QUdOuA{~B!@P7q^SQ!qUXILHsbe(0Ysh2{GG9S}?w z$+qSuAw5?lqecXnIwvSLJ^VK`P~Ki7PgVjn?}es8QneEHVX+rik6+rQKvlYi7F?=pCW5(7%@BpVazzV=5 z5~ctH0l}lH7Z-c4sNdjC9ns6C#$_#BBH5U`fV+G)ls!C}y*3v8$Q6@Hbx|x$RW_SHeE4IP? z^AP>@VKGe5ju2R?FWUH